Dapper Extension Class Mapper - c#

Table -1
Create Table GuestMessageDetails(
id bigint primary key identity(1,1),
companyname varchar(250),
FirstName varchar(250),
FamilyName varchar(250),
EmialAdress varchar(250),
Telephone bigint,
Country varchar(250),
ArticleNumber varchar(250),
SoftwareVersion varchar(250),
SerialNumber varchar(250),
PurchaseDate varchar(250),
OrderNumber varchar(250))
Table -2
Create Table ProductTable (Id bigint primary key identity(1,1),
ArticleImage varchar(250),
ArticleNumber Varchar(250))
model
public class MessageModel
{
public string? companyname { get; set; }
public string? FirstName { get; set; }
public string? FamilyName { get; set; }
public string? EmialAdress { get; set; }
public long Telephone { get; set; }
public string? Country { get; set; }
public string? ArticleNumber {get;set;}
public string? ArticleImage { get; set; }
public string? SoftwareVersion { get; set; }
public string? SerialNumber { get; set; }
public string? PurchaseDate { get; set; }
public string? OrderNumber { get; set; }
}
Now I Want Dapper Extension common two table Class Mapper in Dapper Extension
how create Make Create Respository or Controller
I have Generic Repository Now I Want Two Table Common Generic Class Mapper

You are trying to map two tables with one Model (POCO/Entity) class. This is not supported by Dapper-Extensions.
Dapper-Extensions mapping is something like below:
public sealed class ProductMapper : ClassMapper<Product>
{
public ProductMapper()
{
Schema("dbo");
Table("Products");
Map(x => x.Id).Key(KeyType.Guid);
AutoMap();
}
}
Observe that:
the mapper class is derived from ClassMapper<T> where for T you provide your Model class.
the Table("Products"); call allows to input only one table name.
Dapper-Extensions is designed to generate simple queries for you which may reduce your 80-90% of the SQL code and make it reusable. For any complex scenario, you should fall-back to Dapper. Writing the query by hand helps best in those complex cases.
I am not sure whether creating View on SQL Server and mapping to it will help or not; it may not be practical solution as well.
If you want to use ORM for complex scenario as well, consider using full ORM like NHibernate.

Related

Anonymous type to List of object

I'm using dapper to get data from database which looks as follows (SQL Server)
Column1 column2 column3
Type1 (1,sub1,sub1 descreption),(2,sub2,sub2 description) test
Type2 (3,sub3,sub3 descreption),(4,sub4,sub4 description) test
Classes looks as follows:
public class Types
{
public string Column1 { get; set; }
public IEnumerable<Subs> Column2 { get; set; }
public string Column3 { get; set; }
}
public class Subs
{
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
I'm trying to cast Column2 as IEnumerable and unable to do so. Can someone suggest a way to do it? Do i need to change the way how data is selected from database?
Actually, column 2 should be a table itself with many relations with your current table and what you are currently doing is a very bad practice and can have many downsides.
The right way: Create a table that has Types table Id as foreign key:
CREATE TABLE Subs(
id int,
typeId int foreign key references [Types](id), // you must also add an id could to Types table
name nvarchar(128), //any size that you need it
description nvarchar(max)
)
and the class:
public class Sub
{
public int id { get; set; }
public int typeId {get; set; }
public string name { get; set; }
public string description { get; set; }
}
For how to get one to many relationships with dapper, please see this question:How to query an object with one-to-many relationship using Dapper?

How to model a relationship in EF Core when using custom table and field names

I’m trying to model a relationship between two tables in an existing MsSQL Db using EF Core, but the Db has tables using custom table names and column names.
EF Core is failing to setup the relationship, even though I’m specifying the relationship using either attributes or FluentAPI.
I think the problem is because I have non-convention names for tables and columns and EF is failing to setup the relationship properly.
Here’s the SQL:
CREATE TABLE paid_authors
(
paid_author_id varchar(50) NOT NULL,
[name] varchar(50) NOT NULL
)
CREATE TABLE hardback_books
(
hardback_book_id uniqueidentifier NOT NULL,
paid_author_id varchar(50) NOT NULL,
title varchar(50) NOT NULL
)
INSERT INTO paid_authors VALUES ('duck' ,'Scrooge McDuck')
INSERT INTO hardback_books VALUES (NEWID(), 'duck', 'Duck Tales')
Here’s the C# modelling:
[Table("paid_authors")]
public class PaidAuthor
{
[Key]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
[Column("name")]
public string Name { get; set; }
public virtual List<HardbackBook> HardbackBooks { get; set; }
}
[Table("hardback_books")]
public class HardbackBook
{
[Key]
[Column("hardback_book_id")]
public Guid HardbackBookId { get; set; }
[Column("title")]
public string Title { get; set; }
[ForeignKey("HardbackBooks")] // This could be wrong!
[Column("paid_author_id")]
public string PaidAuthorId {get; set;}
}
My code:
foreach(var author in context.PaidAuthors.Take(10))
{
// This next line makes it work, but it shouldn’t be needed!
// author.HardbackBooks = context.HardbackBooks.Where(x => x.PaidAuthorId == author.PaidAuthorId).ToList();
Console.WriteLine(author.PaidAuthorId + " - " + author.Name);
Console.WriteLine(author.HardbackBooks.Count);
}
When I run the code I get System.NullReferenceException and author.HardbackBooks is null.
I’ve tried FluentAPI, specifying the ForeignKey on the parent class... But there must be something obvious I’m missing! I'm happy to switch to FluentAPI if it can be made to work there.
Needless to say, I can't change the Db structure... :-(
You can't leave the collection Navigation Property null, and should have an inverse Navigation Property on the book. Something like:
[Table("paid_authors")]
public class PaidAuthor
{
[Key]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
[Column("name")]
public string Name { get; set; }
public virtual List<HardbackBook> HardbackBooks { get; } = new HashSet<HardbackBook>();
}
[Table("hardback_books")]
public class HardbackBook
{
[Key]
[Column("hardback_book_id")]
public Guid HardbackBookId { get; set; }
[Column("title")]
public string Title { get; set; }
public PaidAuthor PaidAuthor { get; set; }
[ForeignKey("PaidAuthor")]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
}

Dapper map with prefix in column name

I have 2 classes, Order and Address as following:
public class Order
{
public string OrderId { get; set; }
public Address ShippingAddress { get; set; }
public Address BillingAddress { get; set; }
}
and
public class Address
{
public string Street { get; set; }
public string Town { get; set; }
public string Zip { get; set; }
}
The database stores the orders and address in a single table like this:
CREATE TABLE Orders
(
OrderId NVARCHAR(56) PRIMARY KEY,
BillingStreet NVARCHAR(256),
BillingTown NVARCHAR(256),
BillingZip NVARCHAR(256),
ShippingStreet NVARCHAR(256),
ShippingTown NVARCHAR(256),
ShippingZip NVARCHAR(256)
)
How can i get dapper to map this to the Order class?
Here's how you can do that by making the query generalize the billing and shipping columns and using the version of Query that takes multiple types and telling it to split when it sees a column called "Address". Then you just assign the Address objects to the appropriate property on the Order object.
connection.Query<Order, Address, Address, Order>(
#"SELECT OrderId,
BillingAddress As Address,
BillingTown As Town,
BillingZip As Zip,
ShippingAddress As Address,
ShippingTown As Town,
ShippingZip As Zip,
FROM Orders",
(o, ba, sa) =>
{
o.BillingAddress = ba;
o.ShippingAddress = sa;
return o;
},
splitOn: "Address");
I don't think it is possible with Dapper since it treats row as a single object. It would be possible if you would change your table structure:
CREATE TABLE Orders
(
OrderId NVARCHAR(56) PRIMARY KEY,
BillingAddressId INT
ShippingAddressId INT
)
Then you would have to change your class to:
public class Order
{
public string OrderId { get; set; }
public int ShippingAddressId {get; set;}
public virtual Address ShippingAddress { get; set; }
public int BillingAddressId {get; set;}
public virtual Address BillingAddress { get; set; }
}
And just use multi mapping.
Another option is to use Dapper extensions like Dapper-FluentMap or Dapper Extensions which will help you map columns to classes.

EF abstract base class with key where derived class has different key

Time for a dumb question. I think the database design is screwy, but there isn't much I can do about that part of it. I have a table in the database "Table1" and then "Table2" which is essentially an extension of Table1 (I also have Table3, Table4, etc). My problem is that Table2 has it's own unique key, even though it's a one for one relationship. Then Table2Component uses Table2Id as it's foreign key. However, when I try to use that in my code I think it's pointing to Table1Id. I get the error message:
System.Data.Entity.Edm.EdmAssociationConstraint: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'Table2Id' on entity 'Table2Component' does not match the type of property 'Table1Id' on entity 'Table2' in the referential constraint 'Table2Component_Table2'.
Here is the code
[Table("Table1")]
public abstract class Table1
{
[Key]
[Column("table1_id")]
public string Table1Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("type_cd")]
public string TypeCode { get; set; }
}
[Table("Table2")]
public class Table2 : Table1
{
[Key]
[Column("table2_id")]
public int Table2Id { get; set; }
[ForeignKey("Table1Id")]
public virtual Table1 Table1 { get; set; }
// this table also has a table1_id column
// but I guess I don't need it here, correct?
[Column("column1")]
public string Column1 { get; set; }
public virtual ICollection<Table2Component> Table2Components { get; set; }
}
[Table("Table2Component")]
public class Table2Component : ISubItem
{
[Key]
[Column("table2_component_id")]
public int Table2ComponentId { get; set; }
[Column("table2_id")]
public int Table2Id { get; set; }
[Column("description")]
public string Description { get; set; }
public bool Required { get { return true; } }
[ForeignKey("Table2Id")]
public virtual Table2 Table2 { get; set; }
}
Any suggestions? Should I be more forceful in trying to get the database changed?
Started as comment.... finish as simple answer, since no one else jumped in.
Search for Entity Framework 1:1 relationship eg https://stackoverflow.com/a/14997417/1347784 the restriction is both tables must have the same foreign key when using 1:1
No not necessarily better database design. It is Just the why the EF team built the framework. Ive learnt to live with the restrictions. In code first scenario, no big deal. Try the powertool to reverse engineer the alternative approach when you start with the DB. EF will use 1:M even though you may see it as 1:1. Also OK in my view.

Conditional Mapping of POCO entities using Fluent API

I have this POCO class :
public class MyClass
{
public int MyKey { get; set; }
public string Name { get; set; }
public bool DiscriminatorField { get; set; }
public string AnotherInfo { get; set; }
}
My database model is as such :
Main
ID int
Name varchar
DiscriminatorField bit
Specific1
ID int
AnotherField varchar
Specific2
ID int
AnotherField varchar
The question: Using fluent API (and most likely EntityTypeConfiguration), how can I create this conditional mapping where AnotherField of my entity gets filled by Specific1 if the discriminator is true, and by Specific2 if the discriminator is false?
Note: I do not want to create two different POCOs. I'm looking for something like this, but conditional.
Edit: Added the discriminator field to the POCO entity.

Categories

Resources