2016 年 5 月
第 31 卷,第 5 期
本文章是由機器翻譯。
資料點 - Dapper、Entity Framework 與 Hybrid Apps
此外,您可能已經注意到,我要寫很多 Entity Framework,Microsoft 物件關聯式對應 (ORM) 自 2008年已最主要的.NET 資料存取 API。有其他.NET Orm,但特定的類別,微 Orm,取得大量的較佳的效能注意事項。MICRO-ORM 聽過最提到是 Dapper。什麼是最後引起我感興趣足夠時間來破解某些逾最近已開啟的報告,他們所建立的混合式解決方案使用 EF 和 Dapper,讓每個 ORM 不要它是最適合在單一應用程式的各種開發人員。
讀取許多文章和部落格文章之後,開發人員與聊天,以及玩有點有了 Dapper,我想要分享我的探索,尤其是那些人,我或許聽過了 Dapper,但也不知道或它的運作方式,或是為何人一定會愛上它。請注意,我不是專家。而我知道要滿足我好奇心過,並且希望激起您感興趣,因此您會更進一步深入。
Dapper 的原因?
Dapper 有個有趣的故事,需要從資源,您可能已經非常熟悉繁衍 (spawn) ︰ Marc Gravell Sam Saffron 建置和 Dapper 堆疊溢位,在使用時,才能解決效能問題的平台。堆疊溢位是嚴重的高流量網站,具有指向具有效能問題。根據 [堆疊 Exchange 相關頁面上,堆疊溢位 5.7 億頁面檢視中有 2015年。在 2011 年,Saffron 撰寫部落格張貼有關工作他 Gravell 已經完成,標題為 「 如何我學到來停止擔心和撰寫我自己 ORM 」 (bit.ly),其中說明堆疊碰到的時,其使用 LINQ to SQL 斷電的效能問題。然後,他詳細說明撰寫自訂的 ORM,Dapper,已最佳化的堆疊溢位資料存取的解答。五年後,Dapper 現在是廣泛使用的開放原始碼。Gravell 堆疊和小組成員 Nick Craver 繼續主動管理在專案 github.com/StackExchange/dapper-dot-net。
簡而言之,dapper
Dapper 著重於讓您練習來建構查詢和命令,您認為它們應該是您 SQL 的技巧。它是比更接近 「 裸機 」 標準的 ORM,不但解譯成 SQL 查詢,例如 LINQ to EF 投入時間。Dapper 沒有一些酷炫的轉換功能,例如能夠爆炸清單傳遞給其中 IN 子句。但大多數的情況下,您將傳送至 Dapper SQL 已準備就緒,並查詢更快速地取得資料庫。如果您不擅於 SQL,您可以確定您正在撰寫大部分可能的高效能命令。您需要建立某種類型的 IDbConnection,SqlConnection 與已知的連接字串,例如,為了執行查詢。然後,透過其 API,Dapper 才能執行查詢,以及 — 提供查詢結果的結構描述可以符合目標類型的屬性 — 自動具現化,並填入具有查詢結果的物件。還有另一項值得注意的效能優點如下 ︰ Dapper 實際上會快取它了解,在非常快速的還原序列化期間的後續的查詢所產生的對應。我填入的類別 DapperDesigner (示 [圖 1), ,定義來管理設計人員進行非常 dapper 服裝。
[圖 1 DapperDesigner 類別
public class DapperDesigner
{
public DapperDesigner() {
Products = new List<Product>();
Clients = new List<Client>();
}
public int Id { get; set; }
public string LabelName { get; set; }
public string Founder { get; set; }
public Dapperness Dapperness { get; set; }
public List<Client> Clients { get; set; }
public List<Product> Products { get; set; }
public ContactInfo ContactInfo { get; set; }
}
我要在其中執行查詢的專案有了 Dapper,我擷取透過 NuGet (安裝套件 dapper) 的參考。以下是範例呼叫從 Dapper DapperDesigners 資料表中執行的所有資料列的查詢 ︰
var designers = sqlConn.Query<DapperDesigner>("select * from DapperDesigners");
請注意,在本文中的程式碼清單,我使用 select * 而不是明確地將查詢的資料行投影時我想要從資料表的所有資料行。sqlConn 是我已具現化,以及其連接字串,但沒有開啟過的現有 SqlConnection 物件。
查詢方法是 Dapper 所提供的擴充方法。當執行這一行時,Dapper 開啟連接、 建立 DbCommand、 完全依照我寫了執行查詢、 在結果中每個資料列的 DapperDesigner 物件具現化並將值從查詢結果之物件的屬性。Dapper 可以透過幾種模式符合屬性的結果值,即使屬性名稱不相符的資料行名稱,而且即使屬性不相符的資料行順序相同。它無法讀取則,因此不要期望它找出對應涉及,比方說,許多字串值其中的訂單或資料行和屬性的名稱未同步。我並未嘗試幾個奇數試用看看如何它就會回應,也會控制如何 Dapper 可以推斷出對應的全域設定。
Dapper 及關聯式查詢
我 DapperDesigner 型別有許多關聯性。沒有為一對多 (與產品),一對一 (ContactInfo) 和多對多 (用戶端)。我已實驗跨這些關聯性中,執行查詢,Dapper 可處理的關聯性。它絕對不是十分容易,只要使用 Include 方法或甚至投影表示 LINQ to EF 查詢。我的 TSQL 技能推入限制,不過,因為 EF 允許我過去年變得這麼懶。
跨一個對多關聯性,我會使用資料庫中的權限的 sql 查詢的範例如下 ︰
var sql = @"select * from DapperDesigners D
JOIN Products P
ON P.DapperDesignerId = D.Id";
var designers= conn.Query<DapperDesigner, Product,DapperDesigner>
(sql,(designer, product) => { designer.Products.Add(product);
return designer; });
請注意,查詢方法需要使用指定的類型都必須建構,以及指出要傳回的型別,最後的型別參數 (DapperDesigner) 來表示。我使用多行 lambda 先建構圖形,將相關的產品加入至其父設計工具物件,然後傳回每個設計工具的 ienumerable 查詢方法傳回。
我在 SQL 的最佳嘗試這麼做的缺點是,結果會扁平化,就像使用 EF 包含方法,其方式是一樣。我會收到每項產品的一個資料列與重複的設計工具。Dapper 具有 MultiQuery 方法可傳回多個結果集。結合 Dapper 的 GridReader,這些查詢的效能會明確地財富 EF 包含。
程式碼,更快速地執行更難
表示 SQL 並填入相關的物件是放出 EF,這是絕對加倍努力的程式碼來處理在背景中的工作。但如果您正在使用大量資料,而且執行階段效能很重要,可以肯定是值得的。我的範例資料庫中有 30000 設計工具。只有其中一些產品。我沒有我確定我已比較影響同類一些簡單的基準測試。之前查看測試結果,有幾個重點來了解如何像這些測量結果。
請記住,根據預設,EF 用來追蹤查詢結果的物件。這表示它會建立額外的追蹤物件,其中牽涉到一些工作,而且它還需要將這些追蹤的物件互動。Dapper,相較之下,只是傾印結果至記憶體。因此務必採用 EF 的變更進行任何效能比較時,移至迴圈外追蹤。我這麼做,透過 AsNoTracking 方法定義的所有我 EF 查詢。此外,當比較的效能,您必須套用許多標準的基準測試模式,例如暖機資料庫、 重複多次的查詢和丟出最慢且最快時間。您可以看到我如何建置我下載範例中的效能評定測試的詳細資料。同樣的我認為這些是 「 輕量型 」 的基準測試,只提供了解的差異。針對嚴重的基準測試,您必須重複許多次比我 25 (從開始 500),並在您執行的系統效能的因素。我使用的 SQL Server LocalDB 執行個體,因此我的結果是僅適用於比較的單純性膝上型電腦上執行這些測試。
在我的測試,我正在追蹤的時間可供執行查詢和建置結果。具現化的連線或 DbContexts 不算在內。DbContext 會重複使用讓 EF 來建立記憶體中模型的時間也不會列入帳戶,因為這會只發生一次每個應用程式的執行個體,不會針對每個查詢。
[圖 2 顯示 「 選取 *"的 Dapper 和 EF LINQ 查詢,您可以看到我的測試模式的基本結構測試。請注意,外部收集,我所收集的時間,針對每個反覆項目到清單中 (稱為 「 時間 」) 的實際時間做進一步的分析。
[圖 2 個測試來比較 EF 和 Dapper 時查詢所有 DapperDesigners
[TestMethod,TestCategory("EF"),TestCategory("EF,NoTrack")]
public void GetAllDesignersAsNoTracking() {
List<long> times = new List<long>();
for (int i = 0; i < 25; i++) {
using (var context = new DapperDesignerContext()) {
_sw.Reset();
_sw.Start();
var designers = context.Designers.AsNoTracking().ToList();
_sw.Stop();
times.Add(_sw.ElapsedMilliseconds);
_trackedObjects = context.ChangeTracker.Entries().Count();
}
}
var analyzer = new TimeAnalyzer(times);
Assert.IsTrue(true);
}
[TestMethod,TestCategory("Dapper")
public void GetAllDesigners() {
List<long> times = new List<long>();
for (int i = 0; i < 25; i++) {
using (var conn = Utils.CreateOpenConnection()) {
_sw.Reset();
_sw.Start();
var designers = conn.Query<DapperDesigner>("select * from DapperDesigners");
_sw.Stop();
times.Add(_sw.ElapsedMilliseconds);
_retrievedObjects = designers.Count();
}
}
var analyzer = new TimeAnalyzer(times);
Assert.IsTrue(true);
}
還有其他一點進行關於比較 「 影響同類。 」 Dapper 會在原始 SQL 中使用。根據預設,EF 查詢是表示 linq to EF 而必須通過心力來建置您的 SQL。SQL 建置後,即使 SQL 所使用的參數,它是應用程式的記憶體中快取,讓工作將會減少重複。此外,EF 能夠使用原始的 SQL,因此已經考慮這兩種方法執行查詢。[圖 3 列出四個測試集的比較結果。此下載包含更多測試。
[圖 3 的平均時間,以毫秒為單位來執行查詢,並填入基礎 25 反覆項目,因而不最快速且最慢的物件
* AsNoTracking 查詢 | 關係 | LINQ 到 EF * | EF 原始 SQL * | Dapper 的原始 SQL |
所有設計工具 (30 KB 資料列) | – | 96 | 98 | 77 |
產品 (30 KB 資料列) 的所有設計工具 | 1 : * | 251 | 107 | 91 |
與用戶端 (30 KB 資料列) 的所有設計工具 | * : * | 255 | 106 | 63 |
與連絡人 (30 KB 資料列) 的所有設計工具 | 1 : 1 | 322 | 122 | 116 |
中所示的案例 [圖 3, ,很容易透過 LINQ to Entities 使用 Dapper 的案例。但是,原始的 SQL 查詢的窄差異也不一定是合理的切換到 Dapper 特定工作的系統,否則使用 EF 位置中。當然,您自己的需求會不同,而且可能會影響 EF 查詢與 Dapper 之間的變化程度。不過,在高流量系統中的堆疊溢位,例如,即使毫秒為單位儲存每個查詢的一些可能很重要。
Dapper 和其他持續性需求的 EF
到目前為止測出簡單查詢,我只提取回完全比對屬性所傳回的型別資料表中的所有資料行。只有在您要在查詢投影至類型如果呢嗎? 只要結果的結構描述符合的型別,Dapper 會看到正在建立物件沒有差別。EF,不過,必須多費,如果模型的一部分的型別不符合投影的結果。
DapperDesignerContext 有的 DbSet DapperDesigner 型別。我呼叫 MiniDesigner 具有 DapperDesigner 屬性子集的系統中有另一種類型 ︰
public class MiniDesigner {
public int Id { get; set; }
public string Name { get; set; }
public string FoundedBy { get; set; }
}
MiniDesigner 不是我的 EF 資料模型的一部分,所以 DapperDesignerContext 並不知道此型別。我發現,查詢 30000 的所有資料列,並將投射至 30000 MiniDesigner 物件搭配 EF 比 Dapper 更快 25%已使用原始的 SQL。同樣地,我建議您您自己的效能分析來為您自己的系統做出決定。
Dapper 也可用來與方法可讓您識別哪些屬性必須用於指定的命令,您使用原始的 INSERT 或 UPDATE 命令,或在函式或預存程序在資料庫上執行的參數將資料推送至資料庫。我沒有做任何這些工作的效能比較。
混合式加上在真實世界的 EF Dapper
有許多使用 Dapper 的其資料持續性的 100%的系統。但還記得我感興趣因為指的是混合式解決方案的開發人員而引起。在某些情況下,這些是已備妥 EF 和想要調整的特定問題領域的系統。在其他小組選擇要針對所有的查詢和 EF Dapper 用於所有的儲存。
我問這在 Twitter 上的回應,我會收到不同的意見反應。
@garypochron 告訴他的小組已 」 移動直接與電話方面使用 Dapper 和使用資源檔,以維護 SQL 的組織。 」 若要了解 Simon Hughes (@s1monhughes),作者熱門 EF 反轉 POCO 產生器,在相反方向驚訝 — 將預設為 Dapper 和使用 EF 棘手的問題。他告訴我 」 可能的話,我使用 Dapper。如果它是複雜的更新,我使用 EF。 」
我也看過各種不同的討論,混合式方法受到分離的考量,而不是提高效能。最常見的運用 ASP.NET 身分識別的預設依賴 ef,然後再使用 Dapper 的持續性方案中的其餘部分。
更直接使用資料庫有效能除了其他優點。Rob Sullivan (@datachomp) 以及 Mike Campbell (@angrypets),這兩個 SQL Server 專家喜歡 Dapper。Rob 點出,您可以利用資料庫功能 EF 不提供存取權,例如全文檢索搜尋。長期而言該特定的功能,的確是,關於效能。
相反地,有件事您可以對您無法使用 Dapper 除了變更追蹤的 EF。很好的例子是其中一個我利用建置的方案,我建立了這個發行項時,將資料庫移轉為使用 EF Code First 移轉的模型變更的能力。
Dapper 不是每個人,不過。@damiangray 告訴我 Dapper 辦不到他的解決方案,因為他必須要能夠從其系統的一部分傳回建立 Iqueryable,另一個不是實際的資料。Dapper 的 GitHub 儲存機制,在本主題中,延後的查詢執行帶出 bit.ly/22CJzJl, ,如果您想要閱讀更多相關資訊。設計混合式系統時,使用部分類別的命令查詢分離 (CQS) 讓您設計個別的模型,尋找特定類型的交易 (話的) 時很好的路徑。這樣一來,您不嘗試建置時才能使用 EF 和 Dapper,通常會導致犧牲的每個 ORM 優點香草足夠的資料存取程式碼。就像我處理的這篇文章,Kurt Dowswell 發行 post 呼叫 「 Dapper、 EF 和 CQS 」 (bit.ly/1LEjYvA)。對我而言,並讓您方便好用。
展望未來 CoreCLR 和 ASP.NET 的核心對於,Dapper 發展可支援這些項目,以及。您可以找到詳細資訊,在 Dapper 的 GitHub 儲存機制中的執行緒中 bit.ly/1T5m5Ko。
因此,最後,我探討了 Dapper。我認為?
和我呢? 我不花時間稍早查看 Dapper 後悔一切,很高興我最後完成此步驟。我總是了建議 AsNoTracking 或資料庫中使用檢視或程序來解決效能問題。這永遠不會失敗,我或我的用戶端。但現在我知道我有我套筒建議開發人員感興趣並使用 EF 其系統中發揮更高效能上的另一個技巧。它不是 shoo-in,像我們說的。我的建議會瀏覽 Dapper、 衡量效能差異 (大規模) 以及效能和方便撰寫程式碼之間取得平衡。請考慮 StackOverflow 的明顯使用 ︰ 查詢、 註解問答集,然後傳回一個問題的註解和解答,以及一些中繼資料 (編輯) 和使用者資訊的圖形。它們進行相同類型的查詢,並不斷地對應出的結果相同的圖形。Dapper 被設計來大放異彩這種重複的查詢,每次取得更聰明且更快速。即使您沒有這類的系統需求的 Dapper 所針對的交易數目,您可能發現,混合式解決方案能讓您所需要的結果。
Julie Lerman是 Microsoft MVP、.net 和顧問 Vermont 山區中。您可以找到她針對資料存取和使用者群組和世界各地的研討會其他.NET 主題呈現。她的部落格網址 thedatafarm.com /blog 以及 Code First DbContext 版本中的,所有從 O'Reilly Media 是 「 程式設計 Entity framework 」。在 Twitter 上追蹤她: @julielerman 並查看她 Pluralsight 課程 juliel.me/PS 影片。
感謝下列堆疊溢位技術專家來檢閱這份文件 ︰ Nick Craver 和 Marc Gravell
Nick Craver (@Nick_Craver) 是開發人員、 站台可靠性工程人員,和有時 DBA 的堆疊溢位。他的專長是效能調整圖層,整體系統架構,資料中心硬體,並維護多開放原始碼專案,例如 Opserver。他
Marc Gravell 是在堆疊溢位,開發人員與特定著重於高效能程式庫和.NET 工具,特別是資料存取、 序列化和網路 Api,導致這些區域中的開放原始碼專案的範圍。