I am trying to map my Id fields to the attributes of a column, but for some reason this does not work, and I cannot understand why. I created a test project to demonstrate what I'm trying.
Firstly, I got 2 objects:
Entity Table1
using System.Data.Linq.Mapping; namespace DapperTestProj { public class Table1 { [Column(Name = "Table1Id")] public int Id { get; set; } public string Column1 { get; set; } public string Column2 { get; set; } public Table2 Table2 { get; set; } public Table1() { Table2 = new Table2(); } } }
and the essence of Table2
using System.Data.Linq.Mapping; namespace DapperTestProj { public class Table2 { [Column(Name = "Table2Id")] public int Id { get; set; } public string Column3 { get; set; } public string Column4 { get; set; } } }
In my database, I got 2 tables, also called Table1 and Table2. Both tables got their columns with a name equal to the entity, except that Table1 has a column called Table2Id, and there is also a foreign key between Table1.Table2Id and Table2.Id.
In addition, both tables have 1 record, and they have both identifiers.
What I'm trying to do is execute a query with dapper and it should return an object of type Table1. This works, but the properties of Table1.Id and Table1.Table2.Id remain 0 (the default is an integer). I expect the column attributes to display Id fields, but this is clearly not the case.
This is the query and mapping performed in code:
private Table1 TestMethod(IDbConnection connection) { var result = connection.Query<Table1, Table2, Table1>( @"SELECT T1.Id as Table1Id, T1.Column1 as Column1, T1.Column2 as Column2, T2.Id as Table2Id, T2.Column3 as Column3, T2.Column4 as Column4 FROM Table1 T1 INNER JOIN Table2 T2 ON T1.Table2Id = T2.Id", (table1, table2) => { table1.Table2 = table2; return table1; }, splitOn: "Table2Id" ).SingleOrDefault(); return result; }
Now I could rename both properties of the Id property in essence to Table1Id and Table2Id, but instead I prefer the identifier instead of the more logical code, like Table1.Id instead of Table1.Table1Id. So I was wondering if it is possible that I want here, and if so, how?
Edit:
I found this topic: Manually match column names with class properties
And with the code in the first Kaleb Pederson post, you can use attributes when necessary, with the FallBackTypeMapper class and the ColumnAttributeTypeMapper class. All that is needed is to add the necessary classes to typemapping with:
SqlMapper.SetTypeMap(typeof(Table1), new ColumnAttributeTypeMapper<Table1>()); SqlMapper.SetTypeMap(typeof(Table2), new ColumnAttributeTypeMapper<Table2>());
But with many entities, this list will grow for a long time. You also needed to add each class manually to the list, and I was wondering if this could be done automatically with a more general one with Reflection. I found a piece of code able to get all types:
const string @namespace = "DapperTestProj.Entities"; var types = from type in Assembly.GetExecutingAssembly().GetTypes() where type.IsClass && type.Namespace == @namespace select type;
And fixated on all types, I can do this, only the problem that I have now is what piece of code do I need, or should be placed where the question marks are now?
typeList.ToList().ForEach(type => SqlMapper.SetTypeMap(type, new ColumnAttributeTypeMapper</*???*/>()));
Edit:
After more searching, I found a solution for my last problem:
typeList.ToList().ForEach(type => { var mapper = (SqlMapper.ITypeMap)Activator.CreateInstance( typeof(ColumnAttributeTypeMapper<>) .MakeGenericType(type)); SqlMapper.SetTypeMap(type, mapper); });