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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM