ORM框架工作原理


ORM框架工作原理

所有的ORM框架的工作原理都離不開下面這張圖,只是每個框架的實現程度不同但是最終的目的是相同的。

 

如果是一個ORM框架那么一定會有上圖中藍色部分的這幾個元素,無論是增刪改查對於ORM一定是以對象為起點,使用對象構造出LINQ表達式,這樣我們在對象的世界中可以描述我們希望對數據庫所進行的操作,LINQ的最終實現其實也是Lambda表達式(必盡LINQ在代碼上會直觀很多),功能較強的ORM中都會記錄有對象類型到數據庫對象的元數據,使用這些元數據可以將復雜的Lambda表達式翻譯成一個通用的中間表達式,這個表達式其實是抽象於各個不同數據庫的具體實現,最后中間表達式再按指定數據庫的具體實現生成最終的SQL語句,交由ADO.NET對象執行到數據庫,如果數據存在返回則會回寫到CLR對象中。

ORM框架的優點

  1. 面向對象

  2. 基礎的增刪改查的sql語句會自動生成,無需手動書寫

  3. 編譯檢測(數據庫的表與Domain中的對象一致,否則會報錯)

  4. 不會出現sql語句出錯的情況

ORM框架的缺點

  1. Sql自動生成,不夠靈活,只生成基礎的增刪改查是無法完全適用整個 系統,不確定是否使用索引
  2. 需要很多反射,不管是否有用都會反射出來,對時間空間有耗損
  3. 更新及刪除數據一定要從數據庫取回對象或附加對象才能操作

ORM框架開發的設計流程

以下流程是根據我所接觸的項目中總結出來的,本次是通過EF框架的CodeFirst代碼優先的方式實現的,數據庫里的表對應對象服務Demain中的類,CodeFirst就是實現對象服務Demain與數據的映射。

流程圖如下:

 

 

項目訪問流程:

  1. UI界面層引用實體應用服務(Application)與對象服務(Domain)
  2. 通過抽象工廠從容器中(Container)獲取實體應用服務對象:IDomainApp domainApp = Factory.Create<IDomainApp>();
  3. 實體應用服務通過T4模板生成實體應用接口(IDomainApp.cs)與實體應用接口的實現方法(DomainApp.cs)(T4模板生成方法下面有介紹)
  4. T4模板生成出來的方法存入容器,存入方法:Container.RegisterType<IDomainApp, DomainApp>();
  5. 實體倉儲服務通過T4模板生成實體倉儲接口(IDomainRepository.cs)與實體倉儲接口的實現方法(DomainRepository.cs)(T4模板生成方法下面有介紹)
  6. T4模板生成出來的方法存入容器,存入方法:Container.RegisterType<IDomainRepository, DomainRepository>();
  7. 實體倉儲服務的實體倉儲的實體方法可以直接訪問數據庫,獲取數據,獲取出來的數據以實體對象或者實體對象列表的形式返回給UI界面層的調用方法

  注釋:當前UI界面是通過Linq的查詢方式訪問的實體應用服務,但是訪問實體應用服務不只是局限於Linq查詢方式

項目設計流程中服務的生成

數據庫表的更新:

  1. 在Domian對象服務中生成對象類Domain.cs
  2. 在Repository實體倉儲服務中執行T4模板(執行方法為重新保存 EntityCodeScript.tt文件),執行完成之后則會自動創建實體倉儲操作接口與實體倉儲操作接口的實現
  3. 在Application實體引用服務中更新T4模板(執行方法為重新保存 EntityCodeScript.tt文件),執行完成之后則會自動創建實體應用操作接口與實體應用操作接口的實現
  4. 打開程序包管理器控制台,默認項目選中Repository實體倉儲服務
  5. 在控制台輸入Add-Migration xxx,點擊Enter鍵執行即可(xxx代碼數據庫更新的版本號)
  6. 在控制台輸入update-database 直接更新數據庫,或者輸入 update-database -script查看更新數據庫的sql代碼

實體倉儲服務的更新:

  1. 執行T4模板(執行方法為重新保存 EntityCodeScript.tt文件)生成實體倉儲操作接口(IDomainRepository.cs)與實體倉儲操作接口的實現方法(DomainRepository.cs)
  2. 確認新添加的對象服務類(Domain)是否存在類的映射關系,不存在則實體倉儲服務更新完成
  3. 存在則在Mapping里添加新增的對象服務類(Domain)的實體類型(DomainMap.cs),在實體類型中配置映射關系
  4. 配置完成之后在EntityFrameUnitOfWork中添加實體類型,實現實體類型映射

實體應用服務的更新:

  1. 執行T4模板(執行方法為重新保存 EntityCodeScript.tt文件)生成實體應用操作接口(IDomainApp.cs)與實體應用操作接口的實現方法(DomainApp.cs)
  2. 把實體倉儲服務中新生成的實體倉儲操作接口與實體倉儲操作接口的實現方法寄存在容器(Container)中,Container.RegisterType<IDomainRepository, DomainRepository>();
  3. 把實體應用服務中新生成的實體應用操作接口與實體應用操作接口的實現方法寄存在容器(Container)中,Container.RegisterType<IDomainApp, DomainApp>();

T4模板的設計:

根據對象類的主鍵標識的類型來創建對象類的訪問接口與訪問接口的實現

實體倉儲服務的接口與接口實現如下:

 1 IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => typeof(AggregateRoot<T>).IsAssignableFrom(m) && !m.IsAbstract);
 2 foreach(Type modelType in modelTypes) 3 { 4 T4ModelInfo model = new T4ModelInfo(modelType, true); 5 6 //實體倉儲操作接口 7 IEntityRepositoryTemplate irep= new IEntityRepositoryTemplate(model); 8 var path = string.Format(@"{0}\Auto", projectPath); 9 irep.Output.Encoding = Encoding.UTF8; 10  irep.RenderToFile(Path.Combine(path, irep.FileName)); 11 12 //實體倉儲操作實現 13 EntityRepositoryTemplate rep= new EntityRepositoryTemplate(model); 14 path = string.Format(@"{0}\Auto", projectPath); 15 rep.Output.Encoding = Encoding.UTF8; 16  rep.RenderToFile(Path.Combine(path, rep.FileName)); 17 18 EntityFrameUnitOfWorkTemplate erep= new EntityFrameUnitOfWorkTemplate(model); 19 path = string.Format(@"{0}\Auto", projectPath); 20 erep.Output.Encoding = Encoding.UTF8; 21  erep.RenderToFile(Path.Combine(path, erep.FileName)); 22 }

實體應用服務的接口與接口實現如下:

 1 IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => typeof(AggregateRoot<T>).IsAssignableFrom(m) && !m.IsAbstract);
 2 foreach(Type modelType in modelTypes) 3 { 4 T4ModelInfo model = new T4ModelInfo(modelType, true); 5 6 //實體應用操作接口 7 IEntityAppTemplate irep= new IEntityAppTemplate(model); 8 var path = string.Format(@"{0}\Auto", projectPath); 9 irep.Output.Encoding = Encoding.UTF8; 10  irep.RenderToFile(Path.Combine(path, irep.FileName)); 11 12 //實體應用操作實現 13 EntityAppTemplate rep= new EntityAppTemplate(model); 14 path = string.Format(@"{0}\Auto", projectPath); 15 rep.Output.Encoding = Encoding.UTF8; 16  rep.RenderToFile(Path.Combine(path, rep.FileName)); 17 }

總結:

本文是根據我參與過得項目中總結出來的,也是為了檢驗我對這個項目的理解來做個評判,只是以我自己的理解加看法來解析這個項目以及項目框架的搭建,留作以后作為參考價值使用

以上是我的個人見解,僅供參考。

參考自:

https://www.cnblogs.com/libei/p/10427784.html


免責聲明!

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



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