日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

结婚虽易,终老不易:EntityFramework和AutoMapper的婚后生活

發布時間:2025/3/15 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 结婚虽易,终老不易:EntityFramework和AutoMapper的婚后生活 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面

  • 我到底是什么?
  • 越界的可怕
  • 做好自己
  • 后記

  上一篇《戀愛雖易,相處不易:當EntityFramework愛上AutoMapper》文章的最后提到,雖然AutoMapper為了EntityFramework做了一些改變,然后就看似幸福的在一起了,但是有人(Roger Alsing)看不下去,寫了一篇文章:http://rogeralsing.com/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework-is-horrible/,文中提到EntityFramework和AutoMapper在一起是可怕的,關于這篇英文文章,作為3.5級都考兩次的我來說真是天書,無奈一邊翻譯一邊猜測看了幾遍,英文好的同學可以提供下中文版,因為文章中有代碼,所以作者表達的意思還是可以理解一些。

  文章標題主要關鍵字:mapping DTOs to Entities,注意并不是“Entities?to?DTOs”,表示實體對象到DTO的轉換,并做一些CURD操作,代碼看似合理,但是好像又有些不合理,為什么?主要是對所涉及的概念不清晰,EntityFramework、AutoMapper和DTO,他們到底是什么?有沒有在一起的可能?請接著往下看。

我到底是什么?

  EntityFramework(父親)、AutoMapper(母親)和DTO(孩子)你我都知道的官方定義:

  • EntityFramework:是微軟以 ADO.NET 為基礎所發展出來的對象關系對應 (O/R Mapping) 解決方案。
  • AutoMapper:Object-Object Mapping工具。
  • DTO:數據傳輸對象(Data Transfer Object)。

  EntityFramework的定義中有“ORM“關鍵字,那ORM又是什么?

ORM:對象關系映射(Object/Relation Mapping),是隨著面向對象的軟件開發方法發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流開發方法,關系數據庫是企業級應用環境中永久存放數據的主流數據存儲系統。對象和關系數據是業務實體的兩種表現形式,業務實體在內存中表現為對象,在數據庫中表現為關系數據。內存中的對象之間存在關聯和繼承關系,而在數據庫中,關系數據無法直接表達多對多關聯和繼承關系。 ? --百度百科

  概念清楚了就好辦了,我們再來分析下,從上面定義可以看出:AutoMapper是Object-Object映射工具,EntityFramework是一種ORM框架,DTO是數據傳輸對象(Data Transfer Object),請注意這三個定義中都包含對象(Object)關鍵字,毫無疑問,AutoMapper所做的工作就是ORM中的“O”和DTO中的“O”之間的映射轉換。  

  DTO中的“O”比較好理解,就是數據傳輸對象,不包含任何的業務邏輯,只是存儲數據的一種對象,用于各層之間的數據傳遞。一般的項目都會采用分層設計(也就是常見的三層架構),每一層都是一個相對內聚的設計,一種松耦合結構。而層與層之間進行通訊的就是DTO,而這個“O”常常不是ORM的O。其實也可能不是DomainEntity,也不是ViewModel,但是它卻有可能通過組合、分解等方式進行轉換。

  那ORM中“O”是什么意思?關于ORM的使用,網上有很多的爭論,拋開性能問題,有人提出說“ORM注定了業務邏輯和數據庫的高度耦合”,我覺得這種理解是錯誤的。ORM的“O”是數據對象,與表等有一定的偶合,但它從架構設計上來說,只是倉儲層的內聚設計,與業務邏輯無關(當然現在很多小系統會用它來直接替代業務邏輯對象),而真正的業務邏輯對象(按領域驅動設計來說)是領域對象,真正的的系統核心對象是領域對象,而數據對象是可變的,領域對象則相對穩定,數據對象到領域對象是通過倉儲層的適配器來實現的。

  從上面的結論中可以看出,ORM中的“O”是數據對象。關于數據對象,有人說數據對象是穩定的,那要看數據是基于“數據”的設計,還是基于“對象”的設計。如果是基于“對象”的設計,那么設計之初,就必須把業務對象分析清楚、我們常把它說成領域對象,其實這個對象基本是穩定的(至少核心部分是穩定,如果核心對象變了,那是另一個話題,需求變了),而數據對象可能就不一定了,有可能SqlServer數據有的類型其它數據庫沒有,同樣隨著重構的進行,為了提高性能,可能會對一些表進行拆分和組合,原先在一個表中的數據,分成了兩個表,或在視圖中了。但不管數據表怎么變化,最終也只是倉儲層內部的實現方式變了,當然ORM的“O”也會變,但出了這一層,一切都還是原來的樣子。

  理解這些概念很重要,理解了你會發現,我為什么把EntityFramework看做“父親”,AutoMapper看做“母親”,DTO看做“孩子”,當然這只是某種意義上的關系比作,只有在這三者結合才會出現,比如DTO可以脫離EntityFramework和AutoMapper獨立存在,但他就不是“孩子”的概念了。

越界的可怕

  什么叫越界?就是不是你干的事你卻干了,所做的工作超出自己的范圍之外,Roger Alsing的“Horrible”文章我覺得就是在表達這個意思。AutoMapper的工作范圍只是對象之間的映射轉換,也就是說EntityFramework中的“數據對象”到“DTO”之間的映射轉換,但如果涉及到一些數據訪問或是操作,這就是AutoMapper的越界行為,因為這些操作并不在她的職責范圍之內,而應該是EntityFramework所做的工作。

  某種意義上,可以看做:AutoMapper(母親)只是EntityFramework(父親)和DTO(孩子)之間的橋梁或是溝通,至于賺錢養家的事就交給EntityFramework(父親)去做,如果AutoMapper(母親)幫助EntityFramework(父親)去賺錢養家,可能會造成相反的效果,也就是說AutoMapper(母親)請做好“全職太太”即可。

  我們來看下AutoMapper(母親)的“越界行為”:

1 public void CreateOrUpdateOrder(OrderDTO orderDTO) 2 { 3 var config = new ... 4 5 //create an instanced mapper instead of the static API 6 var mapper = new AutoMapper.MapperEngine(config); 7 var context = ... //get some DbContext 8 9 config.CreateMap<OrderDTO,Order>() 10 .ConstructUsing((OrderDTO orderDTO) => 11 { 12 if (orderDTO.Id == 0) 13 { 14 var order = new Order(); 15 context.OrderSet.Add(order); 16 return order; 17 } 18 return context.OrderSet.Include("Details").First(o => o.Id == orderDTO.Id); 19 }) 20 //find out what details no longer exist in the DTO and delete the corresponding entities 21 //from the dbcontext 22 .BeforeMap((dto, o) => 23 { 24 o 25 .Details 26 .Where(d => !dto.Details.Any(ddto => ddto.Id == d.Id)).ToList() 27 .ForEach(deleted => context.DetailSet.Remove(deleted)); 28 }); 29 30 config.CreateMap<DetailDTO, Detail>() 31 .ConstructUsing((DetailDTO detailDTO) => 32 { 33 if (detailDTO.Id == 0) 34 { 35 var detail = new Detail(); 36 context.DetailSet.Add(detail); 37 return detail; 38 } 39 return context.DetailSet.First(d => d.Id == detailDTO.Id); 40 }); 41 42 mapper.Map<OrderDTO,Order>(orderDTO); 43 44 context.SaveChanges(); 45 }

  AutoMapper的ConstructUsing的用法,我們在:http://www.cnblogs.com/xishuai/p/3704435.html#xishuai_h1中有講解,ConstructUsing表示自定義類型轉換器,發生在映射之前,對映射的操作做一些處理并返回相應的目標類型,注意這里的處理并不是EntityFramework中的持久化,如果在AutoMapper的自定義類型轉換器中做這些操作,就顯得有點不倫不類了。

  關于AutoMapper這樣的“越界行為”,Roger Alsing總結出了其中的優缺點,本人就不翻譯了,以免起到誤讀的效果。

  優點:

  • Looks simple on paper
  • Easy to implement on read side and client side

  缺點:

  • Bloody horrible to implement on the write side, and gets even worse the larger the DTO is
  • Relies on magic names if using AutoMapper
  • Network ineffective if dealing with large DTOs
  • You lose semantics and intentions, there is no way to know WHY a change happened

做好自己

  如果我們在上面代碼中去掉AutoMapper,將會變得如何?請看下面:

1 public void CreateOrUpdateOrder(OrderDTO orderDTO) 2 { 3 var ctx = ... //get some DbContext 4 var order = ctx.OrderSet.FirstOrDefault(o => o.Id == orderDTO.Id); 5 if (order == null) 6 { 7 order = new Order(); 8 ctx.OrderSet.Add(order); 9 } 10 11 //Map properties 12 order.Address = orderDTO.Address; 13 14 //remove deleted details 15 order.Details 16 .Where(d => !orderDTO.Details.Any(detailDTO => detailDTO.Id == d.Id)) 17 .Each(deleted => ctx.DetailSet.Remove(deleted)); 18 19 //update or add details 20 orderDTO.Details.Each(detailDTO => 21 { 22 var detail = order.Details.FirstOrDefault(d => d.Id == detailDTO.Id); 23 if (detail == null) 24 { 25 detail = new Detail(); 26 order.Details.Add(detail); 27 } 28 detail.Name = detailDTO.Name; 29 detail.Quantity = detailDTO.Quantity; 30 }); 31 32 context.SaveChanges(); 33 }

  這樣代碼更加清潔,與使用AutoMapper的代碼形成了明顯的對比,但如果去掉AutoMapper也就失去了DTO的意義,試想沒有母親哪來的孩子?但是如果EntityFramework(父親)、AutoMapper(母親)和DTO(孩子)這三口之家想和諧的生活在一起,那怎么辦?就是AutoMapper只要負責對象映射轉換即可,也就是做EntityFramework(父親)和DTO(孩子)之間的“溝通橋梁”,也就是“全職太太”:

1 Mapper.CreateMap<OrderDTO, Order>(); 2 Mapper.CreateMap<DetailDTO, Detail>(); 3 using (var context = new OrderContext()) 4 { 5 var existOrder = context.Orders.FirstOrDefault(order => order.Id == orderDTO.Id); 6 if (existOrder == null) 7 { 8 var order = Mapper.Map<OrderDTO, Order>(orderDTO); 9 context.Orders.Add(order); 10 context.Details.AddRange(order.Details); 11 context.SaveChanges(); 12 } 13 }

后記

  示例代碼下載:http://pan.baidu.com/s/1o6EzFq6

  做了“全職太太”的AutoMapper,就這樣和EntityFramework幸福的生活下去了,看到這有人又可能有疑問,上篇中AutoMapper為EntityFramework做的IQueryable擴展是不是“越界行為”,注意QueryableExtensions只是AutoMapper所做的擴展,并不是代替EntityFramework去完成持久化操作。

  如果你覺得EntityFramework和AutoMapper可以幸福終老,那就瘋狂的“戳”右下角的“推薦”吧。^_^

  AutoMapper參考文檔:

  • 【AutoMapper官方文檔】DTO與Domin Model相互轉換(上)
  • 【AutoMapper官方文檔】DTO與Domin Model相互轉換(中)
  • 【AutoMapper官方文檔】DTO與Domin Model相互轉換(下)

轉載于:https://www.cnblogs.com/xishuai/p/3720662.html

總結

以上是生活随笔為你收集整理的结婚虽易,终老不易:EntityFramework和AutoMapper的婚后生活的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。