OSS.Core基於Dapper封裝(表達式解析+Emit)倉儲層的構思及實現

来源:http://www.cnblogs.com/osscoder/archive/2017/05/10/6831237.html
-Advertisement-
Play Games

最近趁著不忙,在構思一個搭建一個開源的完整項目,至於原因以及整個項目框架後邊文章我再說明。既然要起一個完整的項目,那麼數據倉儲訪問就必不可少,這篇文章我主要介紹這個新項目(OSS.Core)中我對倉儲層的簡單思考和實現過程(當前項目還處在搭建階段),主要集中在以下幾個方面: 1. 數據倉儲層的需求 ...


    最近趁著不忙,在構思一個搭建一個開源的完整項目,至於原因以及整個項目框架後邊文章我再說明。既然要起一個完整的項目,那麼數據倉儲訪問就必不可少,這篇文章我主要介紹這個新項目(OSS.Core)中我對倉儲層的簡單思考和實現過程(當前項目還處在搭建階段),主要集中在以下幾個方面:

1. 數據倉儲層的需求

2. ORM框架選擇

3. OSS.Core倉儲層設計實現

4. 調用示例

   下邊的實現部分中可能需要你對.NET的 泛型,委托,擴展,表達式等有一個基礎瞭解。正是因為這些語言特性,方便我們對操作共性的抽取統一。

一. 數據倉儲層需求

  既然是一個完整的項目,數據訪問是其最基本的部分,同時,數據訪問也是整個項目最容易出現瓶頸的地方。在我的劃分中,其承擔的角色是負責整個數據的輸入輸出,不僅僅是針對單資料庫(有時甚至多庫),有時還需要完成一級緩存的實現,給邏輯層提供最基礎的數據支撐。

   業務永遠是在變化的,那麼項目也要具備快速演進的能力,所以我希望數據層能夠保持相對的簡單,在結構上儘量減少複雜的耦合查詢,在性能上儘量減少不必要的消耗,例如反射的大量使用。同時針對每個業務對象完成資料庫層面基本的CRUD統一封裝實現。如果有需要的時候還能在最少的改動下加入緩存的更新。(對於如何實現不同模塊不同緩存存儲策略,像Redis,Memcached會在後邊文章介紹)

  同時,對於一個稍微有點規模的項目來說,解決資料庫訪問的最快速做法就是實現讀寫分離,所以,我希望這個框架能夠在一開始在底層就實現了讀寫分離的支持,以避免後期再重頭對業務代碼的大量修改。  

二. ORM 框架選擇

  當然,如果為了簡單和性能,直接ADO.NET連接理論上來說是比較高效的做法,不過這樣會造成大量的重覆操作邏輯代碼,同時也會造成代碼的散亂,增加維護複雜度。作為技術人員,不僅需要解決業務問題提高效率,同時也要提高自己的效率,所以我會選擇一個ORM框架來完成部分基礎工作。

  當前在.NET體系下,開源的ORM框架很多,如:Entityframework,NHibernate,iBATIS.NET,Dapper等等,各有特色,基於前面我說的,保證效率的同時,兼顧簡單還能最大程度減少性能的損耗,並且提供.net standard標準庫下的支持。這裡對比之後我選擇Dapper這個半自動化的ORM作為倉儲層的基礎框架,選擇原因如下:

  1. 其結構簡單,整個封裝主要集中Dapper.cs文件中,體積很小

      2. 封裝功能簡單強大,對原生SQL的支持上很靈活

    這點幾乎完勝其他框架,無需任何多餘的設置,同時基本上你可調用所有原生ADO.NET的功能,sql語句完全自己掌控,卻又無需關心command的參數賦值,以及結果實體轉換等。

  3. 性能上的高效

    很多ORM的實體映射通過反射來完成,這點上Dapper再次展現其魅力,在Commond參數賦值,以及實體轉換等關鍵模塊,使用了Reflection.Emit功能,間接實現了MSIL編譯層面的賦值實現,之所以說間接,是因為其本身代碼還需要編譯器生成IL代碼。在運行時根據類型屬性動態創建賦值委托方法。

 

三. OSS.Core倉儲層設計實現

   通過Dapper可以實現在資料庫訪問部分一層簡單的封裝,不過我依然需要手動編寫不少的sql語句,同時還要進行參數化的處理,包括數據的讀寫分離等。那麼這些功能的實現我將在OSS.Core.RepDapper中完成,為了方便理解,先貼出一個簡單的封裝後的方法調用傳輸流程:

  在這個圖裡展示一個簡單的方法調用流程,圍繞這張圖的幾個核心部分,我分別介紹下:

  1. 介面設計

  因為我希望這個是完整的示例項目,所以後邊希望能夠相容不同資料庫,因此對外的倉儲訪問都基於介面調用。當然如果你的項目根本沒有切換資料庫的需求,我更建議去掉這一環節,直接在基類中實現單例模式,業務邏輯層直接調用。

  圖中可以看到介面層獨立於實現部分,我將具體業務實體模型和介面 單獨放在了OSS.Core.DomainMos 類庫中,一方面是為了實體模型在各模塊中的共用,另一方面解耦業務邏輯層(Services)和倉儲層(Reps)之間的依賴關係。

  同時一個項目中資料庫訪問代碼多數都會以CRUD為主,所以這裡我定義了一個基礎介面(IBaseRep),其包含的方法主要有(表達式部分在後邊介紹):

  具體的業務數據介面繼承至基礎介面就好,其中表達式部分是我自己做了一個封裝,後邊會簡單介紹。

 

  2. 倉儲基類實現(BaseRep

  首先,如圖所示,我們實現了讀寫分離的兩個擴展,其實最終都會經過Excute方法,那麼這裡展示下方法的具體實現:

  可以看到在這個方法提供了一個針對IDbConnection的委托,提供調用層自由使用Dapper方法的同時,統一了數據訪問方法入口,便於日誌記錄,和排查。

 

  其次,在很多項目中會出現用戶和訂單在不同庫中的這類情況,因為涉及到分庫的情況,所以需要子類中能有修改連接串能力,那麼這裡我通過構造函數的形式,提供了兩個可空參數:

  可以看到,如果子類中定義了自己的連接串,則以子類自定義為主,否則走預設的連接信息。

  

  最後,我們也實現了針對基礎介面方法的具體實現,舉一示例:

  同時,為了保證子類中能夠加入緩存處理,所以採用了虛方法(virtual)的形式,保證子類能夠重寫。

 

  3. 基於Connection的擴展

  這個地方主要分為兩個部分,a. 表達式的解析,以及參數化的處理   b. 擴展Connection的Insert,Update...等Dapper沒有擴展的方法:

  a. 熟悉Expression表達式的朋友應該比較瞭解,表達式本身是一個樹形介面,根據不同的類型,可以不斷的解析其子表達式,直到不具備繼續解析的可能。所以這個就很簡單就是遞歸的不斷迭代,根據其不同的NodeType可以組裝不同的sql元素,因為代碼較長,可以參見github下的SqlExpressionVisitor.cs類,其中參數的賦值部分,沒有採用反射,而是使用的反射發射,代碼詳見SqlParameterEmit.cs

  b. 有了表達式的擴展之後,就可以獲取對應的sql和參數,通過this擴展Connection方法即可,代碼見ConnoctionExtention.cs

  

四. 調用示例

  1. 我們定義一個簡單UserInfoMo實體(包含mobile等屬性)

  2. 定義介面  IUserInfoRep: IBaseRep

  3. 定義實現類  UserInfoRep : BaseRep, IUserInfoRep

  在不添加其他代碼的基礎上,我們就可以完成下麵的調用:

 

當前項目還在搭建中,如果有興趣的同學也歡迎參與進來,代碼詳見Github下OSS.Core

 

=============================

如果你還有其他問題,歡迎關註公眾號(OSSCoder)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 0. 寫在前面 1. 建立運行環境 2. 添加實體和映射資料庫 1. 準備工作 2. Data Annotations 3. Fluent Api 3. 包含和排除實體類型 1. Data Annotations [NotMapped] 排除實體和屬性 2. Fluent API [Ignore] ...
  • 如果需要集合中的元素何時刪除或添加的信息,可以使用ObservableCollection<T>類。這個類是為WPF定義的,這樣UI就可以得知集合的變化。這個類在程式集WindowsBase中定義,需要引用這個程式集。 ObservableCollection<T>類派生自Collection<T> ...
  • 包含不重覆元素的集合稱為“集(set)”。.NET Framework包含兩個集HashSet<T>和SortedSet<T>,它們都實現ISet<T>介面。HashSet<T>集包含不重覆元素的無序列表,SortedSet<T>集包含不重覆元素的有序列表。 ISet<T>介面提供的方法可以創建合集 ...
  • ListView是個較為複雜的控制項 ListView是個較為複雜的控制項 ListView是個較為複雜的控制項 1.定義 把它拽進來,系統會自動在Designer.cs里添加一個 this.listView1 = new System.Windows.Forms.ListView(); 2.初始化,確定 ...
  • 字典表示一種複雜的數據結構,這種數據結構允許按照某個鍵來訪問元素。字典也稱為映射或散列表。 字典的主要特性是能根據鍵快速查找值。也可以自由添加和刪除元素,這有點像List<T>(http://www.cnblogs.com/afei-24/p/6824791.html),但沒有在記憶體中移動後續元素的 ...
  • 1 /// 2 /// 短鏈生成 3 /// 4 public class ShortUrlBuilder 5 { 6 private static readonly string[] Chars = 7 { "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h"... ...
  • 一、確定多線程的結束時間,thread的IsAlive屬性 在多個線程運行的背景下,瞭解線程什麼時候結束,什麼時候停止是很有必要的。 案例:老和尚念經計時,2本經書,2個和尚念,一人一本,不能撕破,最短時間念完,問老和尚們念完經書最短需要多長時間。 分析:首先在開始念經的時候給計時,記為A,最後在記 ...
  • MVVM的目標之一就是為瞭解耦View和ViewModel。View負責視圖展示,ViewModel負責業務邏輯處理,儘量保證 View.xaml.cs中的簡潔,不包含複雜的業務邏輯代碼。 但是在實際情況中是View和ViewModel之間的交互方式還是比較複雜的,View和ViewModel的分離 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...