Dapper数据库字段和model属性映射

背景:
在.net core 2.0 Asp.mvc 项目中使用dapper 框架

一、
数据库字段名和model属性名一一对应时,直接只用dapper方法是没有问题的,比如:

//实体类
public class Books
{
[Dapper.Key]
public int Id { get; set; }

public string Name { get; set; }

public string Author { get; set; }
}
数据库:book表

直接使用dapper对象的方法,传入model对象:

//默认映射
string sql = $"SELECT * FROM book ";
database.QueryListSQL<ReadBooks>(sql).ToList();

//直接传入实体对象
bool result = await database.CreateAsync(book) > 0;
好处是不需要在sql语句中将字段一个个写出来,直接使用table-model映射关系,非常便利!

二、
但是,也会有字段名和属性名不对应的情况,比如:

public class ReadBooks
{

public DateTime CreateTime { get; set; }
}


那么,在C#程序中,使用Dapper做查询时,如何配置数据表字段(列)和实体类属性之间的映射呢?

method 1:
查询时,可以在select语句中使用AS别名,别名与model对应:

var sql = @"select create_time AS CreateTime from book";
database.Single<Books>(sql);
插入/更新时,依然需要 列名-值 :

//dapper插入语句,表名和字段名
database.InsertSQL($@"book",new DataColumn("Author", book.Author),
new DataColumn("Name", book.Name),
new DataColumn("create_time", DateTime.Now)
);
 
method 2:
查询时,还可以使用Linq:

//搭配动态类型dynamic使用

List<Books> book= database.Query<dynamic>(sql)
.Select(item => new Books()
{
CreatTime= creat_time
}
.ToList();
method 3:
如果有很多数据库表字段和model属性不对应的话,我们每次都使用别名和linq就有些麻烦,如果能像EF那样,在model属性上加一个Attribute来表明字段和属性映射关系就好了,EF:

class School
{
/*
若属性名和数据库字段不一致(不区分大小写)则查询不出数据,如果使用EF则可以通过Column特性
建立属性和数据表字段之间的映射关系,Dapper则不行
*/
//[Column("Name")]
public string Title { set; get; }
public string Address { set; get; }
}
Dapper虽然有colmun的特性,但是并不能完成字段-属性映射;

我们需要手动拓展一个colmun特性出来,以完成如EF的绑定。

1,添加一个类ColumnAttributeTypeMapper,用于字段-属性映射:

using Dapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace 命名空间
{

/// <summary>
/// Uses the Name value of the <see cref="ColumnAttribute"/> specified to determine
/// the association between the name of the column in the query results and the member to
/// which it will be extracted. If no column mapping is present all members are mapped as
/// usual.
/// </summary>
/// <typeparam name="T">The type of the object that this association between the mapper applies to.</typeparam>
public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
public ColumnAttributeTypeMapper()
: base(new SqlMapper.ITypeMap[]
{
new CustomPropertyTypeMap(
typeof(T),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<ColumnAttribute>()
.Any(attr => attr.Name == columnName)
)
),
new DefaultTypeMap(typeof(T))
})
{
}
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ColumnAttribute : Attribute
{
public string Name { get; set; }
}

public class FallbackTypeMapper : SqlMapper.ITypeMap
{
private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;

public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
{
_mappers = mappers;
}


public ConstructorInfo FindConstructor(string[] names, Type[] types)
{
foreach (var mapper in _mappers)
{
try
{
ConstructorInfo result = mapper.FindConstructor(names, types);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}

public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetConstructorParameter(constructor, columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}

public SqlMapper.IMemberMap GetMember(string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetMember(columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}


public ConstructorInfo FindExplicitConstructor()
{
return _mappers
.Select(mapper => mapper.FindExplicitConstructor())
.FirstOrDefault(result => result != null);
}
}


}
2,再添加一个类ColumnMapper,用于添加映射关系:

using Dapper;
using 引入需要的.Models;

namespace 项目命名空间
{
public class ColumnMapper
{
public static void SetMapper()
{
//数据库字段名和c#属性名不一致,手动添加映射关系
SqlMapper.SetTypeMap(typeof(Books), new ColumnAttributeTypeMapper<Books>());

//每个需要用到[colmun(Name="")]特性的model,都要在这里添加映射
}
}
}
3,在starup.cs类的中方法注册:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSession();

//调用前面的静态方法,将映射关系注册
ColumnMapper.SetMapper();
}
4,最后就可以在model的属性名上添加特性来映射到数据库字段名了:

using 引入新加的类.Helper;

public class Books
{
[Column(Name = "create_time")]
public DateTime CreateTime { get; set; }
}
这样我们就可以在所有的不与数据库对应的model中,方便的添加映射关系了!
————————————————
版权声明:本文为CSDN博主「Zdelta」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Zdelta/java/article/details/87636491

原文地址:https://www.cnblogs.com/deepalley/p/13307445.html