背景:
在.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