在使用Entity Framework 實體架構的時候,我們大多數時候操作的都是實體模型Entity,這個和資料庫操作上下文結合,可以利用LINQ等各種友善手段,實作起來非常友善,一切看起來很美好。但是如果考慮使用WCF的時候,可能就會碰到很多相關的陷阱或者錯誤了。因為實體模型Entity的對象可能包括了其他實體的引用,在WCF裡面就無法進行序列化,出現錯誤;而且基于WCF的時候,可能無法有效利用Express表達式,無法直接使用LINQ等問題都一股腦出現了。本文基于上面的種種問題,闡述了我的整個Entity Framework 實體架構的解決思路,并且在其中引入了資料傳輸模型DTO來解決問題,本文主要介紹資料傳輸模型DTO和實體模型Entity的分離與聯合,進而實作我們通暢、高效的WCF應用架構。
例如,我們定義的Entity Framework 實體類裡面包含了其他對象的引用,例如有一個Role對象,有和其他表的關聯關系的,預設使用傳統方式,在實體類裡面添加[DataContract]方式。
在WCF服務接口裡面使用代碼如下所示。
那麼我們在WCF裡面使用的時候,會得到下面的提示。
接收對 http://localhost:11229/Service1.svc 的 HTTP 響應時發生錯誤。這可能是由于服務終結點綁定未使用 HTTP 協定造成的。這還可能是由于伺服器中止了 HTTP 請求上下文(可能由于服務關閉)所緻。有關詳細資訊,請參見伺服器日志。
預設情況下,Entity Framework為了支援它的一些進階特性(延遲加載等),預設将自動生成代理類是設定為true。如果我們需要禁止自動生成代理類,那麼可以在資料庫操作上下文DbContext裡面進行處理設定。
如果設定為false,那麼WCF服務可以工作正常,但是實體類對象裡面的其他對象集合則為空了,也就是WCF無法傳回這些引用的内容。
同時,在Entity Framework架構裡面,這種把實體類貫穿各個層裡面,也是一種不推薦的做法,由于WCF裡面傳輸的資料都是序列号過的資料,也無法像本地一樣利用LINQ來實作資料的處理操作的。
那麼我們應該如何建構基于WCF引用的Entity Framework實體架構呢?
前面介紹了直接利用Entity Framework實體類對象的弊端,并且如果是一路到底都使用這個實體類,裡面的很多對象引用都是空的,對我們在界面層使用不便,而且也可能引發了很多WCF架構裡面的一些相關問題。
我們根據上面的問題,引入了一個DTO(資料傳輸對象)的東西。
資料傳輸對象(DTO)是沒有行為的POCO對象,它的目的隻是為了對領域對象進行資料封裝,實作層與層之間的資料傳遞,界面表現層與應用層之間是通過資料傳輸對象(DTO)進行互動的。資料傳輸對象DTO本身并不是業務對象,資料傳輸對象是根據UI的需求進行設計的。
這個對象和具體資料存儲的實體類是獨立的,它可以說是實體類的一個映射體,名稱可以和實體類不同,屬性數量也可以實體類不一緻。那麼既然在實體對象層外引入了另外一個DTO對象層,那麼互相轉換肯定是避免不了的了,我們為了避免手工的映射方式,引入了另外一個強大的自動化映射的工具AutoMapper,來幫助我們快速、高效、智能的實作兩個層對象的映射處理。

AutoMapper的使用比較簡單,一般如果對象屬性一直,他們會實作屬性自動映射了,如下所示。
如果兩者的屬性名稱不一緻,那麼可以通過ForMember方式指定,類似下面代碼所示。
AutoMapper也可以把映射資訊寫到一個類裡面,然後統一進行加載。
那麼基于上面的圖示模式,由于我們采用代碼生成工具自動生成的DTO和Entity,他們屬性名稱是保持一緻的,那麼我們隻需要在應用層對它們兩者對象進行互相映射就可以了。
基于這個内部對接的映射關系,我們就可以在Facade接口層提供統一的DTO對象服務,而業務邏輯層(也就是利用Entity Framework 實體架構的處理成)則依舊使用它的Entity對象來傳遞。下面我提供幾個封裝好的基類接口供了解DTO和Entity的互相銜接處理。
1)傳入DTO對象,并轉換為Entity對象,使用EF對象插入。
2)根據條件從EF架構中擷取Entity對象,并轉換後傳回DTO對象
3)根據條件從EF架構中擷取Entity集合對象,并轉換為DTO清單對象
基于友善管理的目的,每個子產品都可以采用一種固定分層的方式來組織子產品的業務内容,每個子產品都是以麻雀雖小、五髒俱全的方針實施。執行個體子產品的整個業務邏輯層的項目結構如下所示。
如果考慮使用WCF,那麼整體的結構和我之前的混合架構差不多,各個子產品的職責基本沒什麼變化,不過由原先在DAL層分開的各個實作層,變化為各個資料庫的Mapping層了,而模型增加了DTO,具體項目結構如下所示。
具體的項目說明如下所示:
EFRelationship
系統的業務子產品及接口、資料庫通路子產品及接口、DTO對象、實體類對象、各種資料庫映射Mapping類等相關内容。該子產品内容緊密結合Database2Sharp強大代碼生成工具生成的代碼、各層高度抽象繼承及使用泛型支援多資料庫。
EFRelationship.WCFLibrary
系統的WCF服務的業務邏輯子產品,該子產品通過引用檔案方式,把業務管理邏輯放在一起,友善WCF服務部署及調用。
EFRelationshipService
架構WCF服務子產品,包括基礎服務子產品BaseWcf和業務服務子產品,他們為了友善,分開管理釋出。
EFRelationship.Caller
定義了具體業務子產品實作的Façade應用接口層,并對Winform調用方式和WCF調用方式進行包裝的項目。
具體我們以一個會員系統設計為例,它的程式集關系如下所示。
我們來看看整個架構的設計效果如下所示。
其中業務邏輯層子產品(以及其它應用層)我們提供了很多基于實體架構的公用類庫(WHC.Framework.EF),其中的繼承關系我們将它放大,了解其中的繼承細節關系,效果如下所示。
上圖很好的概述了我的EF實體架構的設計思路,這些層最終還是通過代碼生成工具Database2Sharp進行一體化的生成,以提高快速生産的目的,并且統一所有的命名規則。後面有機會再寫一篇随筆介紹代碼生成的邏輯部分。
上圖左邊突出的兩個工廠類,一個IFactory是基于本地直連方式,也就是直接使用EF架構的對象進行處理;一個CallerFactory是基于Facade層實作的接口,根據配置指向WCF資料服務對象,或者直連對象進行資料的操作處理。
這個系列文章如下所示:
<a href="http://www.cnblogs.com/wuhuacong/p/4336248.html">Entity Framework 實體架構的形成之旅--基于泛型的倉儲模式的實體架構(1)</a>
<a href="http://www.cnblogs.com/wuhuacong/p/4338564.html">Entity Framework 實體架構的形成之旅--基類接口的統一和異步操作的實作(3)</a>
<a href="http://www.cnblogs.com/wuhuacong/p/4338982.html">Entity Framework 實體架構的形成之旅--實體資料模型 (EDM)的處理(4)</a>
<a href="http://www.cnblogs.com/wuhuacong/p/4372674.html">Entity Framework 實體架構的形成之旅--Code First模式中使用 Fluent API 配置(6)</a>
<a href="http://www.cnblogs.com/wuhuacong/p/4449059.html">Entity Framework 實體架構的形成之旅--資料傳輸模型DTO和實體模型Entity的分離與聯合</a>