輕量級ORM框架Dapper應用之實現(xiàn)DTO
一、什么是DTO
先來看看百度百科的解釋:
數(shù)據(jù)傳輸對象(DTO)(Data Transfer Object),是一種設計模式之間傳輸數(shù)據(jù)的軟件應用系統(tǒng)。數(shù)據(jù)傳輸目標往往是數(shù)據(jù)訪問對象從數(shù)據(jù)庫中檢索數(shù)據(jù)。數(shù)據(jù)傳輸對象與數(shù)據(jù)交互對象或數(shù)據(jù)訪問對象之間的差異是一個以不具有任何行為除了存儲和檢索的數(shù)據(jù)(訪問和存取器)。
二、為什么需要DTO
在一個軟件系統(tǒng)的實現(xiàn)中,我們常常需要訪問數(shù)據(jù)庫,并將從數(shù)據(jù)庫中所取得的數(shù)據(jù)顯示在用戶界面上。這樣做的一個問題是:用于在用戶界面上展示的數(shù)據(jù)模型和從數(shù)據(jù)庫中取得的數(shù)據(jù)模型常常具有較大區(qū)別。在這種情況下,我們常常需要向服務端發(fā)送多個請求才能將用于在頁面中展示的數(shù)據(jù)湊齊。
三、使用Dapper實現(xiàn)DTO
使用Dapper可以直接返回DTO類型,包括兩種方式:
新建Category、ProductDetail和ProductDTO實體類:
Category實體類定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DapperConvertDto
{
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
}ProductDetail實體類定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DapperConvertDto
{
public class ProductDetail
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public double Price { get; set; }
public int CategoryId { get; set; }
}
}ProductDTO實體類定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DapperConvertDto
{
public class ProductDto
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public double ProductPrice { get; set; }
public string CategoryName { get; set; }
}
}ProductDTO實體類中的ProductPrice對應ProductDetail表的Price,CategoryName對應Category表的CategoryName。
方式一:直接在SQL語句中使用as
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
namespace DapperConvertDto
{
class Program
{
static void Main(string[] args)
{
// 數(shù)據(jù)庫連接
string strCon = @"Initial Catalog=StudentSystem; Integrated Security=False;User Id=sa;Password=1qaz@WSX;Data Source=127.0.0.1;Failover Partner=127.0.0.1;Application Name=TransForCCT";
SqlConnection conn = new SqlConnection(strCon);
// 方式一:直接在SQL語句中使用as,將查詢的字段轉換成DTO類型的屬性
string strSql = @" SELECT p.ProductId,p.ProductName,p.Price AS ProductPrice,c.CategoryName FROM Category c INNER JOIN ProductDetail p ON c.CategoryId=p.CategoryId ";
ProductDto product = conn.Query<ProductDto>(strSql).FirstOrDefault<ProductDto>();
}
}
}結果:

從截圖中看出,返回的就是想要的DTO類型。
方式二:使用委托的方式進行映射,分別把Category和ProductDetail實體類里的屬性,映射成ProductDTO類型的屬性:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
namespace DapperConvertDto
{
class Program
{
static void Main(string[] args)
{
// 數(shù)據(jù)庫連接
string strCon = @"Initial Catalog=StudentSystem; Integrated Security=False;User Id=sa;Password=1qaz@WSX;Data Source=127.0.0.1;Failover Partner=127.0.0.1;Application Name=TransForCCT";
SqlConnection conn = new SqlConnection(strCon);
// 方式一:直接在SQL語句中使用as,將查詢的字段轉換成DTO類型的屬性
string strSql = @" SELECT p.ProductId,p.ProductName,p.Price AS ProductPrice,c.CategoryName FROM Category c INNER JOIN ProductDetail p ON c.CategoryId=p.CategoryId ";
ProductDto product = conn.Query<ProductDto>(strSql).FirstOrDefault<ProductDto>();
// 方式二:使用委托進行自定義映射
string strSql2 = @" SELECT p.ProductId,p.ProductName,p.Price,c.CategoryName FROM Category c INNER JOIN ProductDetail p ON c.CategoryId=p.CategoryId ";
// 定義映射的委托
Func<ProductDetail, Category, ProductDto> map = (p, c) =>
{
ProductDto dto = new ProductDto();
dto.ProductId = p.ProductId;
dto.ProductName = p.ProductName;
dto.ProductPrice = p.Price;
dto.CategoryName = c.CategoryName;
return dto;
};
// splitOn表示查詢的SQL語句中根據(jù)哪個字段進行分割
string splitOn = "CategoryName";
List<ProductDto> list = conn.Query<ProductDetail, Category, ProductDto>(strSql2, map, splitOn: splitOn).ToList<ProductDto>();
}
}
}結果:

注意:
1、splitOn
splitOn表示查詢的SQL語句中按照哪個字段進行分割,splitOn的順序是從右向左的,遇到splitOn設置的字段接結束,把從右邊開始到設置的這個字段歸為同一個實體。例如:上面的例子中,splitOn設置為CategoryName,則表示從右邊開始,到CategoryName為止的所有字段都是屬于Category這個實體的,剩余的字段都是屬于ProductDetail實體的。
2、注意委托中實體類的前后順序
委托中實體類的前后順序一定要和查詢的SQL語句中字段的前后順序一致,上面的例子中先查詢的ProductDetail、后查詢的Category,那么定義委托的時候,要先寫ProductDetail,后寫Category,如果委托中實體類的順序錯了,那么不會得到映射的數(shù)據(jù),看下面的例子:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
namespace DapperConvertDto
{
class Program
{
static void Main(string[] args)
{
// 數(shù)據(jù)庫連接
string strCon = @"Initial Catalog=StudentSystem; Integrated Security=False;User Id=sa;Password=1qaz@WSX;Data Source=127.0.0.1;Failover Partner=127.0.0.1;Application Name=TransForCCT";
SqlConnection conn = new SqlConnection(strCon);
// 方式一:直接在SQL語句中使用as,將查詢的字段轉換成DTO類型的屬性
string strSql = @" SELECT p.ProductId,p.ProductName,p.Price AS ProductPrice,c.CategoryName FROM Category c INNER JOIN ProductDetail p ON c.CategoryId=p.CategoryId ";
ProductDto product = conn.Query<ProductDto>(strSql).FirstOrDefault<ProductDto>();
// 方式二:使用委托進行自定義映射
string strSql2 = @" SELECT p.ProductId,p.ProductName,p.Price,c.CategoryName FROM Category c INNER JOIN ProductDetail p ON c.CategoryId=p.CategoryId ";
// 定義映射的委托
//Func<ProductDetail, Category, ProductDto> map = (p, c) =>
//{
// ProductDto dto = new ProductDto();
// dto.ProductId = p.ProductId;
// dto.ProductName = p.ProductName;
// dto.ProductPrice = p.Price;
// dto.CategoryName = c.CategoryName;
// return dto;
//};
// 錯誤的委托
Func<Category, ProductDetail, ProductDto> map = (c,p) =>
{
ProductDto dto = new ProductDto();
dto.ProductId = p.ProductId;
dto.ProductName = p.ProductName;
dto.ProductPrice = p.Price;
dto.CategoryName = c.CategoryName;
return dto;
};
// splitOn表示查詢的SQL語句中根據(jù)哪個字段進行分割
string splitOn = "CategoryName";
List<ProductDto> list = conn.Query< Category, ProductDetail, ProductDto>(strSql2, map, splitOn: splitOn).ToList<ProductDto>();
}
}
}結果:

到此這篇關于使用Dapper實現(xiàn)DTO的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
.NET 6開發(fā)TodoList應用之使用AutoMapper實現(xiàn)GET請求
我們希望接受的請求和返回的值具有以下兩點需要遵循的原則:每個model被且只被一個API消費;每個model里僅僅包含API發(fā)起方希望包含的必要字段或?qū)傩?。AutoMapper庫就是為了實現(xiàn)這個需求而存在的。本文將為大家介紹AutoMapper如何實現(xiàn)GET請求,需要的可以參考一下2021-12-12
.NET中RDLC循環(huán)處理數(shù)據(jù)的應用分析
本篇文章介紹了,.NET中RDLC循環(huán)處理數(shù)據(jù)的應用分析。需要的朋友參考下2013-05-05

