If the query column names do not match your classes you can setup mappings for types. This example demonstrates mapping using System.Data.Linq.Mapping.ColumnAttribute
as well as a custom mapping.
The mappings only need to be setup once per type so set them on application startup or somewhere else that they are only initialized once.
Assuming the same query as the One-to-many example again and the classes refactored toward better names like so:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Born { get; set; }
public Country Residience { get; set; }
public ICollection<Book> Books { get; set; }
}
public class Country
{
[System.Data.Linq.Mapping.Column(Name = "CountryId")]
public int Id { get; set; }
[System.Data.Linq.Mapping.Column(Name = "CountryName")]
public string Name { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
}
Note how
Book
doesn't rely onColumnAttribute
but we would need to maintain theif
statement
Now place this mapping code somewhere in your application where it is only executed once:
Dapper.SqlMapper.SetTypeMap(
typeof(Country),
new CustomPropertyTypeMap(
typeof(Country),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<System.Data.Linq.Mapping.ColumnAttribute>()
.Any(attr => attr.Name == columnName)))
);
var bookMap = new CustomPropertyTypeMap(
typeof(Book),
(type, columnName) =>
{
if(columnName == "BookId")
{
return type.GetProperty("Id");
}
if (columnName == "BookName")
{
return type.GetProperty("Name");
}
throw new InvalidOperationException($"No matching mapping for {columnName}");
}
);
Dapper.SqlMapper.SetTypeMap(typeof(Book), bookMap);
Then the query is executed using any of the previous Query<>
examples.
A simpler way of adding the mappings is shown in this answer.