為什麼需要建立另外一種資料模型?
那麼為什麼需要建立另外一種模型呢?隨著公司資料處理量的增加,理順資料關係並基於這些資料來開發應用程式變得非常困難。資料庫結構描述的設計需要考慮儲存問題(如資料完整性、效能和管理),有時候這不是很容易理解。這些架構還經常與應用程式的結構有衝突,使開發和維護工作變得更加複雜。
我們經常會遇到資料結構與所構建的應用程式被分割開的自訂解決方案。遺憾地是,對每個應用程式而言,自訂解決方案的數量、各種各樣的方法以及建模資料所需的步驟都各不相同,導致問題不斷產生。整個行業都希望能有一種方法來針對應用程式級的領域模型進行定義和開發,以便能夠與邏輯模型的儲存清晰地分隔開。因此引入了Entity Framework。
EDM允許以組織看待和使用資料的方式(不是資料的儲存方式)來定義領域模型。開發 EDM 還有一個主要目標,那就是在 Microsoft 內成為用於開發人員和伺服器技術套件的核心資料模型。
通過使用一個核心資料模型,應用程式的維護得以簡化。實現此目標後,EDM 即可發揮作用,不但可以為基於 ADO.NET Entity Framework 構建的自訂應用程式定義模型,還可以作為報告和可視化應用程式、Intranet 門戶應用程式或工作流程應用程式的輸入內容。
與 ER 模型類似,EDM 使用以下兩個主要概念:實體(事物)以及這些實體之間的關係(或關聯)。在考慮實體和關聯執行個體(或這些執行個體集操作的封閉包)的儲存時,還需要用到“集”的概念。因此,更清楚地說,實體存在於 EntitySet 中而關聯存在於 AssociationSet 中。
在 EDM 中定義的最後一個結構概念是 EntityContainer 概念,它可以在之前介紹的執行個體和關係集周圍定義一個封閉包。這些簡單概念在聯合使用後可允許開發人員定義一個領域模型,此模型可被映射回持久性層和在應用程式自身中使用的類。(需要注意的是,EDM 的持久性層不需要是相關的,儘管它現在是相關的。)
EDM 中定義的每個實體類型可包含兩個不同類型的成員,一個是用來定義實體的屬性(類似於資料庫中的列),另一個是導覽屬性,它支援實體類型參與的導航關係(通常表示為資料庫中的外鍵)。此外,每個實體類型都必須有一個唯一的標識或關鍵字。
為什麼使用 XML 來描述 EDM?
經過認真考慮後,XML 被選作 EDM 的第一個序列表示。通過產生 XML 檔案(或資源)或從動態產生的 XML 表示中載入,開發人員和第三方可以利用經過良好定義的 XML 格式來進行此類格式的轉換以及將其載入到Entity Framework的中繼資料運行時中。但是,建立 EDM 的其他表示也是完全可能的,而且很可能隨著產品的發展在未來版本中就會出現其他替代表示。
當前的 EDM 文法是使用產品隨附的 XML 結構定義語言 (XSD) 定義的。但是,不應期望大多數人都會採用手動開發 XML 的方式,而應認為人們會使用 Visual Studio 中提供的工具。也就是說,團隊已知曉大家對特定領域語言 (DSL) 以及對 EDM 模型備用持久性機制(通常針對資料庫而言)的關注,並且正在對這些選項做評估以便在即將發行的版本中進行擴充。
誰需要另一種新的查詢語言?
有關 EDM 開發的最後一個問題是為什麼要建立一種新的查詢語言?為什麼不使用現有的語言?在稍微深入地研究一個 EDM 後,答案就會變得清晰起來。
到目前為止,我已經介紹了為什麼要建立 EDM 以及 EDM 中使用的各種構造,還介紹了這樣一個事實,即該模型是實體關聯模型的後代。為了使建立的模型不但能夠清楚地映射到底層資料存放區,而且還可以表現開發人員編程時所依據的應用程式級的領域模型,EDM 需要能夠對各種概念(如繼承和多態性)進行建模。由於當前的關係查詢語言並不支援基於繼承、關係導航或多態結果的傳回值進行查詢,因此需要開發一種新的查詢語言來滿足此需求。
這就催生了實體 SQL (ESQL),它是一種新的 SQL 語言,其中加入了之前的 SQL 語言並不支援的基於概念的查詢功能。ESQL 擴充現有 SQL 語言的方式與 EDM 擴充資料庫中所使用的關聯式模式的方式十分類似。此外,ESQL 未綁定到任何特定於後台資料庫的文法,因此可一次性編寫查詢(和/或應用程式),無論針對的是哪個後台資料庫都無影響。下面我將以一個簡單的 ESQL 查詢為例,說明如何從全部部落格中檢索至少具有一篇文章和關聯人員(在我的模型中是指部落格所有者)的部落格:
select c, c.Person from travelEntitiesGeneral.Blogs as c where c.BlogPosts.Count > 0
實現 EDM
ADO.NET Entity Framework 是由 ADO.NET 演變而來的,是 EDM 的首個具體實現,可在開發關聯式資料庫時提供較進階別的抽象。在版本 1.0 中,團隊一直側重於構建平台基礎,而不僅僅是一個簡單的 ORM,這將允許開發人員使用非常靈活的映射來處理概念性模型或物件模型,並能夠適應與底層儲存之間存在的巨大分別。
這一高度的靈活性以及與底層儲存的巨大分別是允許資料庫和應用程式分別發展的關鍵所在。當資料庫結構描述發生改變時,應用程式由於採用Entity Framework而不必進行改動,並且您通常不需要重新編寫應用程式的內容,只是在必要時更新對應檔以適應此變化即可。
為了開始發展 ADO.NET 平台,需要以現有 ADO.NET 2.0 提供者模型為基礎構建Entity Framework,並對現有提供者進行適當更新以支援新的Entity Framework和 ADO.NET 3.5 功能。我們之所以選擇在現有 ADO.NET 提供者模型的基礎上來實現是為了確保開發社區對提供者模型不會感到陌生。
體繫結構 1 所示。您會注意到可接受的架構包括概念結構定義語言 (CSDL)、映射架構語言以及存放結構定義語言 (SSDL)。您還會注意到,Entity Framework包括了更新後的支援規範命令樹 (CCT) 的 SqlClient 資料提供者。
圖 1 ADO.NET Entity Framework 體繫結構
EntityClient
然後,Entity Framework在這些 ADO.NET 3.5 提供者的基礎上引入新的 ADO.NET 提供者 EntityClient。EntityClient 看上去與之前使用的 ADO.NET 提供者非常類似,它將提供第一個抽象,可允許開發人員使用標準的 Connection、Command 和 DataReader 對象依照 EDM 執行查詢。它還會將映射領域模型所需的用戶端視圖引擎(根據 EDM 定義的)添加到底層關聯式資料庫架構。必要時,EntityClient 可藉助 ESQL 查詢字串讓開發人員以行和列的形式處理實體,而不必產生類來表示概念架構。
在這第一個階段中,命令樹仍針對 EDM 來表示。用戶端視圖引擎借鑒資料庫系統中的具體化檢視理論並將這些理論應用到資料訪問層,它在樹中應用了一個映射轉換,可產生一個在底層邏輯儲存模型方面表示相同操作的樹,並刪除任何非關係概念(如關係、繼承和多態性)。這一新轉換的樹被傳給 ADO.NET 3.5 提供者服務,而此服務會返回封裝底層儲存的本機 SQL 的 DbCommand 命令,然後此命令被執行,其結果通過堆棧向上回傳。
在定義用戶端視圖引擎中所使用的映射以便在 EDM 和邏輯資料庫結構描述之間進行轉換時,可採用多種不同的方法。此映射可使用對應規格語言 (MSL) 來指定,這是一種聲明性的 XML 文法,可通過手動編寫 XML 或使用 Visual Studio 中包括的實體映射工具進行建立和編輯。
編譯時間,MSL 允許Entity Framework產生必要的查詢並更新視圖,這些視圖隨後會在用戶端視圖引擎中被用來完成從查詢(利用 EDM 定義的)到邏輯儲存架構的轉換。
另一種用於表達映射或部分映射的方法是使用 ESQL 查詢。在這種情況下,當開發人員使用 ESQL 來表達查詢檢視時,基礎結構會要求他們在映射規範中同時定義伴隨的 Create、Update 和 Delete 映射。此操作是必需的,因為如果能夠在“查詢檢視”中利用 ESQL 功能,從而可以為沒有單個有效更新視圖的查詢定義視圖,則映射基礎結構將無法為查詢產生對應的更新視圖。
物件服務
在 EntityClient 提供者的基礎上,Entity Framework添加了另一組抽象,以便允許針對對象而非 EntityClient 返回的非類型化資料記錄進行開發。這就是通常被認為是 ORM 的層,它可以產生在資料模型中所定義類型的 CLR 執行個體並允許開發人員使用 LINQ 或 ESQL 查詢這些對象。它也恰好是當初眾多開發人員在市場中尋找可用的 ORM 技術時最能吸引他們眼球的Entity Framework層。
物件服務層的進階功能是接受來自應用程式的 ESQL 或 LINQ 查詢,然後將查詢運算式傳遞給下面的 EntityClient 並返回 IEnumerable<T>。但是,經過深入的分析後您會發現,物件服務層的中心是代表應用程式與底層資料存放區之間的互動會話的 ObjectContext。
ObjectContext 是開發人員在查詢、添加和刪除其實體執行個體以及將新狀態儲存回資料庫時用到的主要構造。
如果使用物件服務,則對開發人員而言,跟蹤記憶體中對象所發生的更改的流程以及將這些更改儲存回資料庫的流程都會得到簡化。物件服務使用 ObjectStateManager 不但會跟蹤記憶體中執行個體的目前狀態,還會跟蹤每個執行個體從存放庫中檢索出來時的初始狀態,從而使Entity Framework可以在將資料推送回資料庫時應用最優的並行作業。通過對 ObjectContext 調用 SaveChanges 方法,可以輕鬆地儲存所跟蹤的更改並將其推送回資料存放區庫。
到目前為止,我一直在講述有關 ObjectContext 的基本內容並通過一些樣本介紹 ObjectContext 的基本用法,它通常用於有動態工具或應用程式需要使用 EDM 模型的情形。但是,在使用 Visual Studio 作為開發環境時,開發人員發現強型別化 ObjectContext 還有一個優點,即可以向可能特定於目標 EDM 的表面功能添加屬性和方法。
LINQ to Entities 是作為物件服務上一個非常薄的層出現的,它在程式設計語言中提供直接的查詢功能而非使用基於字串的查詢。在這種情況下,ObjectQuery 類將實現 Iqueryable,允許它接受 LINQ 運算式樹狀架構,並採用物件服務在將 ESQL 查詢傳遞到 EntityClient 提供者時所使用的同樣方式在執行個體架構中推動查詢(作為 CCT 查詢運算式)。
預設情況下,無論是從 Visual Studio 中的 EDM 產生的還是使用 edmgen.exe(Entity Framework隨附的命令列工具)產生的 CLR 類都是 XML 可序列化和二進位可序列化的,並且是導覽屬性預設設定為 DataMembers 的資料約定,因而可以建立 ASMX Web 服務並在檢視狀態或 WCF 服務中使用實體執行個體。
與大多數 ORM 類似,Entity Framework目前並不支援使用資料操作語言 (DML) 進行建立、更新或刪除等操作。必須將更改應用到記憶體中的對象,並且在構建要保持的整個圖表時可能需要與資料庫進行多次互動。