如何使用Dapper處理多個(gè)結(jié)果集與多重映射實(shí)例教程
前言
對(duì)象關(guān)系映射(ORM)已經(jīng)被使用了很長(zhǎng)時(shí)間,以解決在編程過(guò)程中對(duì)象模型與數(shù)據(jù)模型在關(guān)系數(shù)據(jù)庫(kù)中不匹配的問(wèn)題。
Dapper是由Stack OverFlow團(tuán)隊(duì)開(kāi)發(fā)的開(kāi)源的,輕量級(jí)的ORM.相比于其他的ORM框架,Dapper速度非???。
Dapper的設(shè)計(jì)考慮到了性能以及易用性。它支持使用事務(wù),存儲(chǔ)過(guò)程或數(shù)據(jù)批量插入的靜態(tài)和動(dòng)態(tài)對(duì)象綁定。
在本文中,我們將介紹如何使用DAPPER從單個(gè)數(shù)據(jù)庫(kù)調(diào)用中讀取數(shù)據(jù)庫(kù)中的多個(gè)結(jié)果集。我們將看看我們可能希望這樣做的場(chǎng)景,以及如何使用它的Query和QueryMultiple方法更簡(jiǎn)潔地實(shí)現(xiàn)這一點(diǎn)。 當(dāng)我們談?wù)撘詳?shù)據(jù)為中心的應(yīng)用程序時(shí),可能會(huì)出現(xiàn)一些場(chǎng)景,在這些場(chǎng)景中我們可能希望從數(shù)據(jù)庫(kù)中檢索多重結(jié)果。多個(gè)結(jié)果集既可以是相關(guān)的,也可以是無(wú)關(guān)的。要做到這一點(diǎn),我們不需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行多次往返,而是可以在一次數(shù)據(jù)庫(kù)調(diào)用本身中實(shí)際使用dapper檢索結(jié)果,然后將結(jié)果映射到代碼中的所需對(duì)象。
在我們繼續(xù)并開(kāi)始研究如何做到這一點(diǎn)之前,讓我們首先試著理解在我們的應(yīng)用程序中可能希望做到這一點(diǎn)的場(chǎng)景:
1、查詢無(wú)關(guān)實(shí)體:所請(qǐng)求的實(shí)體根本不相關(guān)。
2、查詢具有1至多個(gè)關(guān)系的相關(guān)實(shí)體:被請(qǐng)求的實(shí)體具有1對(duì)多的關(guān)系,我們需要在代碼中處理多個(gè)結(jié)果集
3、查詢具有1至1關(guān)系的相關(guān)實(shí)體:被請(qǐng)求的實(shí)體具有1-1關(guān)系,我們需要在代碼中執(zhí)行處理多個(gè)映射 在第一個(gè)場(chǎng)景中,我們有完全不相關(guān)的實(shí)體,因此基本上,我們只想執(zhí)行兩個(gè)獨(dú)立的查詢來(lái)檢索數(shù)據(jù),然后將其映射到這些實(shí)體。在第二個(gè)場(chǎng)景中,返回的實(shí)體與1-多相關(guān),因此我們希望檢索數(shù)據(jù),然后將結(jié)果映射到具有1至多個(gè)關(guān)系的POCO中。
最后,在第三個(gè)場(chǎng)景中,返回的實(shí)體是1-1,因此我們希望檢索數(shù)據(jù),然后將結(jié)果映射到具有1-1關(guān)系的POCO中。 現(xiàn)在讓我們看看一些代碼,了解如何使用Dapper來(lái)實(shí)現(xiàn)這一切。 所有這些都可以通過(guò)DAPPER的查詢、QueryMultiple和Read方法進(jìn)行歸檔。現(xiàn)在讓我們把重點(diǎn)放在如何在代碼中執(zhí)行這些操作。
查詢無(wú)關(guān)實(shí)體
假設(shè)我們想從API中檢索書(shū)籍和視頻列表。我們可以通過(guò)兩個(gè)簡(jiǎn)單的選擇所有查詢來(lái)實(shí)現(xiàn)這一點(diǎn),數(shù)據(jù)庫(kù)結(jié)果看起來(lái)如
現(xiàn)在,為了能夠從代碼中執(zhí)行同樣的操作,我們首先需要定義我們的實(shí)體:
public class Book { public int ID { get; set; } public string BookName { get; set;} public string ISBN { get; set; } } public class Video { public int ID { get; set; } public string VideoName { get; set; } }
使用這些模型,讓我們看看如何只使用一個(gè)數(shù)據(jù)庫(kù)調(diào)用來(lái)使用DAPPER檢索這些結(jié)果:
public IActionResult Index() { // define our SQL query - it contains mulitple queries seprated by ; var query = "SELECT * from Books; Select * from Videos"; // Execute the query var results = dbConnection.QueryMultiple(query); // retrieve the results into the respective models var books = results.Read<Book>(); var videos = results.Read<Video>(); return Ok(new { Books = books, Videos = videos}); }
現(xiàn)在讓我們?cè)赑OSTMAN中運(yùn)行,以查看行動(dòng)中的結(jié)果:
注意:我已經(jīng)創(chuàng)建了一個(gè)簡(jiǎn)單的API控制器來(lái)測(cè)試這個(gè)代碼,所有的DB訪問(wèn)代碼都在里面運(yùn)行。這只是為了演示目的和現(xiàn)實(shí)世界的應(yīng)用,這樣的代碼根本不應(yīng)該被使用。
查詢具有1到多關(guān)系的查詢相關(guān)實(shí)體
檢索相關(guān)實(shí)體的另一個(gè)典型場(chǎng)景是實(shí)體之間存在一對(duì)多關(guān)系。讓我們嘗試使用組織和聯(lián)系人的例子來(lái)可視化這一點(diǎn)。組織通常具有與其關(guān)聯(lián)的多個(gè)聯(lián)系人。如果我們想要檢索一個(gè)組織,并且想要檢索所有關(guān)聯(lián)的聯(lián)系人,我們可以利用QueryMultiple來(lái)做到這一點(diǎn)。這就是關(guān)系在數(shù)據(jù)庫(kù)中的樣子。
首先讓我們檢查一下如何使用SQL查詢做同樣的操作。
現(xiàn)在,如果我們必須在代碼中做同樣的事情,我們首先需要定義我們的實(shí)體。請(qǐng)注意,我們的實(shí)體也將建模一對(duì)多關(guān)系的方式,每個(gè)組織有一個(gè)聯(lián)系人列表。
public class Organization { public int ID { get; set; } public string OrganizationName { get; set; } public List<contact> Contacts { get; set; } } public class Contact { public int ID { get; set; } public int OrganizationId { get; set; } public string ContactName { get; set; } } </contact>
現(xiàn)在讓我們看一下用于檢索這些相關(guān)實(shí)體的代碼,并了解如何用dapper的QueryMultiple方法填充與1到多個(gè)關(guān)系相關(guān)的實(shí)體。
[HttpGet("{id}")] public IActionResult GetOrganization(int id) { // define our SQL query - it contains mulitple queries seprated by ; var query = @"SELECT* from Organizations where id = @id; Select * from Contacts where OrganizationId = @id"; // Execute the query var results = dbConnection.QueryMultiple(query, new { @id = id }); // retrieve the results into the respective models var org = results.ReadSingle<Organization>(); org.Contacts = results.Read<Contact>().ToList(); return Ok(org); }
在上面的代碼中,我們可以看到我們是如何同時(shí)執(zhí)行2個(gè)查詢的。我們接受了第一個(gè)查詢結(jié)果并填充了我們的組織對(duì)象。第二個(gè)查詢結(jié)果作為同一個(gè)組織對(duì)象的聯(lián)系人集合被推送。
現(xiàn)在讓我們?cè)赑OSTMAN中運(yùn)行,以查看行動(dòng)中的結(jié)果:
具有1到1關(guān)系的查詢相關(guān)實(shí)體
前兩個(gè)場(chǎng)景非常簡(jiǎn)單,因?yàn)樗鼈円笪覀兙帉?xiě)兩個(gè)獨(dú)立的查詢,然后獨(dú)立收集每個(gè)查詢的結(jié)果,以便根據(jù)需要?jiǎng)?chuàng)建模型對(duì)象。
但是有1到1個(gè)關(guān)系的場(chǎng)景是很棘手的。從數(shù)據(jù)庫(kù)的角度來(lái)看,我們可以在單個(gè)SQL查詢本身中檢索相關(guān)實(shí)體,但是隨后我們希望將單個(gè)結(jié)果集映射到代碼中的多個(gè)對(duì)象中。這可以使用在DAPPER中可用的多重映射特征來(lái)完成。讓我們?cè)谝粋€(gè)例子的幫助下理解這一點(diǎn)。
注意:我們?nèi)匀豢梢允褂门c1到許多關(guān)系相同的方法來(lái)檢索與1到1相關(guān)的數(shù)據(jù),但是本節(jié)將展示如何使用單個(gè)SQL并映射結(jié)果。
讓我們舉一個(gè)聯(lián)系和護(hù)照的例子。每個(gè)聯(lián)系人只能有一個(gè)護(hù)照。讓我們先想象一下這個(gè)數(shù)據(jù)庫(kù)關(guān)系。
現(xiàn)在,讓我們看看是否需要從數(shù)據(jù)庫(kù)中檢索聯(lián)系人列表及其護(hù)照信息,我們?nèi)绾斡肧QL實(shí)現(xiàn)這一點(diǎn)。
現(xiàn)在讓我們看看我們的實(shí)體如何尋找聯(lián)系和護(hù)照。
public class Contact { public int ID { get; set; } public int OrganizationId { get; set; } public string ContactName { get; set; } public Passport Passport { get; set; } } public class Passport { public int ID { get; set; } public int Contactid { get; set; } public string PassportNumber { get; set; } }
現(xiàn)在讓我們看看如何從數(shù)據(jù)庫(kù)中檢索這些相關(guān)實(shí)體,并使用更簡(jiǎn)潔的多重映射完整地填充具有相同關(guān)系的POCOs。
[HttpGet("{id}")] public IActionResult GetContact(int id) { var query = @"Select c.ID, c.Organizationid, c.ContactName, p.ID as PassPortId, p.ContactId, p.PassportNumber from Contacts c, Passports p where c.ID = p.ContactID and c.id = @id"; // Execute the query var contact = dbConnection.Query<Contact, Passport, Contact>(query, MapResults, new { @id = id }, splitOn: "PassportId"); return Ok(contact); } private Contact MapResults(Contact contact, Passport passport) { contact.Passport = passport; return contact; }
在上面的代碼中,我們使用的是查詢方法的重載版本,它采用多個(gè)類型。傳遞的類型是我們要映射的每個(gè)對(duì)象的類型參數(shù),最后一個(gè)類型參數(shù)是表示該查詢將返回的對(duì)象類型的附加參數(shù)。
因此,在我們的查詢中,我們希望將結(jié)果映射到類型Contact和Passsport,然后期望結(jié)果返回到類型Contact的對(duì)象中。
現(xiàn)在,讓我們看看在查詢方法中傳遞的實(shí)際參數(shù)。
第一個(gè)參數(shù)是SQL查詢本身。
第二個(gè)參數(shù)是映射函數(shù),它將獲取結(jié)果,將它綁定到相應(yīng)的類型,然后創(chuàng)建所需的返回類型并返回該返回類型。在我們的代碼中,它采用Contact和Passport類型,并將Contact的Passport屬性指定為正在傳遞的Passport值。一旦這樣做,結(jié)果接觸類型返回。
第三個(gè)參數(shù)是命令參數(shù)@ id。
最后一個(gè)參數(shù)拆分是將告訴DAPPER哪些列必須映射到下一個(gè)對(duì)象的列名。在我們的示例中,我們將此值作為PassportId傳遞,這意味著在找到PassportId列之前,所有列都將映射到第一種類型,即Contact,然后隨后的列將被映射到下一個(gè)參數(shù)類型,即Passport。
注意:如果我們有2個(gè)以上的對(duì)象需要映射,splitOn將是一個(gè)逗號(hào)分隔的列表,其中每個(gè)列名將充當(dāng)分隔符,并開(kāi)始下一個(gè)對(duì)象類型的映射列。
現(xiàn)在讓我們?cè)赑OSTMAN中運(yùn)行,以查看行動(dòng)中的結(jié)果:
歐了,我們使用DAPPER從數(shù)據(jù)庫(kù)中檢索多個(gè)結(jié)果集,以避免數(shù)據(jù)庫(kù)往返。
總結(jié):
在本文中,我們討論了如何使用dapper提供的特性在一次運(yùn)行中檢索多個(gè)相關(guān)或無(wú)關(guān)的實(shí)體,從而避免多次數(shù)據(jù)庫(kù)往返。這是從初學(xué)者的角度寫(xiě)的。我希望這有一定的信息性。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
C#截取中英文混合指定長(zhǎng)度字符串實(shí)例
這篇文章主要介紹了C#截取中英文混合指定長(zhǎng)度字符串,大家參考使用2013-12-12.NET實(shí)現(xiàn):將EXE設(shè)置開(kāi)機(jī)自動(dòng)啟動(dòng)
.NET實(shí)現(xiàn):將EXE設(shè)置開(kāi)機(jī)自動(dòng)啟動(dòng)的方法,需要的朋友可以參考一下2013-03-03關(guān)于c#二叉樹(shù)的實(shí)現(xiàn)
本篇文章小編為大家介紹,關(guān)于c#二叉樹(shù)的實(shí)現(xiàn)。需要的朋友參考下2013-04-04C# 制作PictureBox圓形頭像框并從數(shù)據(jù)庫(kù)中讀取頭像
C#提供的PictureBox控鍵默認(rèn)情況下是方形的非常大的影響美觀,怎么解決這一問(wèn)題呢?下面小編給大家?guī)?lái)了C# 制作PictureBox圓形頭像框并從數(shù)據(jù)庫(kù)中讀取頭像的操作代碼,感興趣的朋友一起學(xué)習(xí)下吧2021-08-08C#實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟
這篇文章主要為大家介紹了C#如何實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟功能,本案例涉及的知識(shí)點(diǎn)包含:Process、Shell32.dll、User32.dll、Struct數(shù)據(jù)結(jié)構(gòu),感興趣的可以了解一下2022-09-09C#中GridView動(dòng)態(tài)添加列的實(shí)現(xiàn)方法
這篇文章主要介紹了C#中GridView動(dòng)態(tài)添加列的實(shí)現(xiàn)方法,涉及C#中GridView的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07C# 實(shí)現(xiàn)dataGridView選中一行右鍵出現(xiàn)菜單的示例代碼
這篇文章主要介紹了C# 實(shí)現(xiàn)dataGridView選中一行右鍵出現(xiàn)菜單,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09C#畫(huà)筆使用復(fù)合數(shù)組繪制單個(gè)矩形的方法
這篇文章主要介紹了C#畫(huà)筆使用復(fù)合數(shù)組繪制單個(gè)矩形的方法,涉及C#使用畫(huà)筆繪制圖形的相關(guān)技巧,需要的朋友可以參考下2015-06-06