Entity Framework

Entity Framework (又稱ADO.NET Entity Framework) 是微軟以 ADO.NET 為基礎所發展出來的物件關聯對應 (O/R Mapping) 解決方案，早期被稱為 ObjectSpace，包含在 .NET Framework中發表。從版本6開始獨立發佈。

**背景**
長久以來，程式設計師和資料庫總是保持著一種微妙的關係，在商用應用程式中，資料庫一定是不可或缺的元件，這讓程式設計師一定要為了連接與存取資料庫而去學習 SQL 指令，因此在資訊業中有很多人都在研究如何將程式設計模型和資料庫整合在一起，物件關聯對應 (Object-Relational Mapping) 的技術就是由此而生，像Hibernate或NHibernate都是這個技術下的產物，而微軟雖然有了ADO.NET這個資料存取的利器，但卻沒有像NHibernate這樣的物件對應工具，因此微軟在.NET Framework 2.0發展時期，就提出了一個ObjectSpace的概念，ObjectSpace可以讓應用程式可以用完全物件化的方法連接與存取資料庫，其技術概念與NHibernate相當類似，然而ObjectSpace工程相當大，在.NET Framework 2.0完成時仍無法全部完成，因此微軟將ObjectSpace納入下一版本的.NET Framework中，並且再加上一個設計的工具（Designer），構成了現在的 ADO.NET Entity Framework。
Entity Framework是ADO.NET之上支持面向數據應用程序開發，使得開發者工作於領域相關的對象和屬性的數據級，如客戶、客戶地址等，不必關注存儲數據的底層表、列。這種在更高層次上創建、維護面向數據的應用程序可以大大節約編碼量。
Entity Framework 利用了抽象化資料結構的方式，將每個資料庫物件都轉換成應用程式物件 (entity)，而資料欄位都轉換為屬性 (property)，關聯則轉換為結合屬性 (association)，讓資料庫的 E/R 模型完全的轉成物件模型，如此讓程式設計師能用最熟悉的程式語言來呼叫存取。而在抽象化的結構之下，則是高度整合與對應結構的概念層、對應層和儲存層，以及支援 Entity Framework 的資料提供者 (provider)，讓資料存取的工作得以順利與完整的進行。- 概念層：負責向上的物件與屬性顯露與存取。- 對應層：將上方的概念層和底下的儲存層的資料結構對應在一起。- 儲存層：依不同資料庫與資料結構，而顯露出實體的資料結構體，和 Provider 一起，負責實際對資料庫的存取和 SQL 的產生。

**歷史**
2008年8月11日，Entity Framework的第一版(EFv1)隨.NET Framework 3.5 Service Pack 1和Visual Studio 2008 Service Pack 1發佈。該版受到了廣泛的批評。
2010年4月12日，Entity Framework第2版，稱為Entity Framework 4.0 (EFv4)發佈，解決了第一版的很多問題。該版本完全包含在.NET Framework中。
2011年4月12日發佈了Entity Framework第3個版本，稱為version 4.1，開始支持Code First。2011年7月25日發佈了Entity Framework 4.1 Update 1。
2012年2月29日發佈了version 4.3.1。
2012年8月11日發佈了Version 5.0.0。與.NET framework 4.5配套。
2013年10月17日發佈了Version 6.0。併成為開源軟件，使用Apache License v2. 類似於ASP.NET MVC，開源發佈於GitHub。 This version has a number of improvements for code-first support.Entity Framework 6.0、6.1、6.2、6.3 和 6.4 完全作為NuGet包提供。
2014年5月19日，微軟決定為了讓其.NET能跨平臺，下一版Entity Framework將完全重寫。2016年6月27日，發佈了Entity Framework Core 1.0, 伴隨著ASP.NET Core 1.0 和 .NET Core 1.0.本來其命名為Entity Framework 7，但為了突出其是完全重寫而不是替換EF6所以重新命名。

**架構**
ADO.NET Entity Framework 架構圖
ADO.NET Entity Framework架構，從底向上包括：- Data source specific providers, ADO.NET抽象接口連接到數據庫。- Map provider, 特定數據庫的provider，翻譯Entity SQL命令樹到數據庫本地SQL方言查詢。包括Store-specific bridge，負責把一般命令樹翻譯為存儲特定的命令樹。 - EDM parser and view mapping, 把數據模型的特定的SDL規範和如何映射到關係模型。從關係模式角度，它創建了對應於概念模型的數據views。它聚合（aggregate）多張表的信息成為一個實體（entity），把一個到實體的修改（update）分割為到多個表的修改。- Query and update pipeline, 處理查詢、過濾器、修改等請求，轉化為經典命令樹。 - Metadata services, 處理實體、關係、映射的所有元數據。- Transactions, 集成基礎存儲的事務能力。如果基礎存儲不支持事務，則在這個層次上實現事務。 - Conceptual layer API, 提供了概念模式下的編程接口。遵從ADO.NET模式，使用Connection對象引用map provider, 使用Command對象發送查詢，返回EntityResultSets 或 EntitySets 以包含結果。- Disconnected components, ADO.NET Entity Framework使用的本地緩存數據集和實體集，在偶爾連接環境。- Embedded database: ADO.NET Entity Framework包含一個輕量嵌入數據庫用於客戶端緩存和查詢關係數據庫。 - Design tools, 如Mapping Designer, ADO.NET Entity Framework包含的用於簡化映射從概念模式到關係模式，指出實體類型的哪些屬性映射到數據庫的哪個表。 - Programming layer, 暴露EDM作為編程結構，可被編程語言使用
** Object services, 自動產生CLR類代碼，把同一屬性作為一個實體，允許實體實例作為.NET 對象.
** Web services, 暴露web服務的實體- High-level services, 如工作在實體上的報告服務。

**概念層結構**
概念層結構定義了物件模型 (Object Model)，讓上層的應用程式碼可以如物件導向的方式般存取資料，概念層結構是由 CSDL (Conceptual Schema Definition Language) 所撰寫。
一份概念層結構定義如下所示：













**對應層結構**
對應層結構負責將上層的概念層結構以及下層的儲存體結構中的成員結合在一起，以確認資料的來源與流向。對應層結構是由 MSL (Mapping Specification Language) 所撰寫。
一份對應層結構定義如下所示：









**儲存層結構**
儲存層結構是負責與資料庫管理系統（DBMS）中的資料表做實體對應 (Physical Mapping)，讓資料可以輸入正確的資料來源中，或者由正確的資料來源取出。它是由 SSDL (Storage Schema Definition Language) 所撰寫。
一份儲存層結構定義如下所示：














**Entity Data Model**
Entity Data Model (EDM) 給出數據的概念模型(CSDL) ，這所使用的建模技術被稱為Entity Data Model, 是實體-關係模型的擴展版。數據模型主要描述了實體和其涉及的關聯（Association）。EDM模式用Schema Definition Language (SDL)表述，這事XML的一種應用。此外，從概念模式(CSDL)到存儲模式(SSDL)的映射(MSL)也必須用XML表示。
Visual Studio提供了Entity Designer 可視化創建EDM和映射規範。該工具輸出XML文件(*.edmx)來描述這種模式和映射。Edmx文件包含EF元數據(CSDL/MSL/SSDL內容)。也可手工編輯這3個文件(csdl, msl, ssdl)。

**Mapping**
Visual Studio的Entity Data Model Wizard在大部分情況下最初產生數據庫模式和概念模式的1對1映射。關係模式下，表和主鍵、外鍵組成元素。“實體類型”定義了概念模式下的數據。
實體類型是多個類型字段的聚合，每個字段映射到數據庫的特定列，可以包含來自多個物理表的信息。實體類型可以彼此有關係，且獨立於物理模式內的關係。相關的實體可以通過字段的名字表示這種關係，以代替從數據庫的列獲取值，通過這種字段可以遍歷相關的實體，返回一個實體或實體集合。 
實體類型形成了對象的類，實體是整個類型的實例。實體是應用程序的單個對象，用一個鍵索引。
ADO.NET Entity Framework使用Entity Data Model (EDM)表示這種映射。
ADO.NET Entity Framework使用eSQL，SQL的一個派生，來執行查詢、集合論操作、修改實體及其關係。

**實體**
實體是“實體類型”的實例，表示單個對象的實例（如“客戶”、“訂單”）。ADO.NET Entity Framework中的實體屬性是完全類型化的，完全兼容於DBMS的類型系統和.NET Framework的Common Type System。屬性可以是SimpleType或ComplexType或多值的。所有EntityType屬於某個命名空間，幷包含一個EntityKey屬性。
所有實體實例在EntityContainers中。每個項目有一個或多個EntityContainers。
EDM基礎類型(簡單類型):

**關係**
任何兩個實體類型可以是相關的，或者是Association關係或者Containment關係。用Relationship Type來表示。
關係類型用degree (arity)和multiplicity刻畫。ADO.NET Entity Framework支持二元雙向關係，multiplicity包括一對一、一對多、多對多。實體間的關係是有名的，稱為Role。定義了關係的目的。
關係類型可以有Operation或Action。例如，刪除一個實體，其關聯的關係可以採取：- Cascade：刪除關係實例和所有相關聯的實體實例。- None.


**模式定義語言**
ADO.NET Entity Framework使用基於XML的數據定義語言稱為 Schema Definition Language (SDL)定義EDM Schema。SDL定義了SimpleTypes類似於CTS基礎類型，包括String, Int32, Double, Decimal, Guid, 和 DateTime等等。枚舉類型定義了基礎值和其名字的映射，也被認為是簡單類型。ComplexTypes為其他類型的聚合。屬性的集合定義了實體類型。寫為巴恩斯瑙爾範式：
EntityType ::= 
ENTITYTYPE entityTypeName BASE entityTypeName
false KEY propertyName , propertyName    {(propertyName PropertyType PropertyFacet*) +}
PropertyType ::= (
(PrimitiveType PrimitiveTypeFacets*)

(complexTypeName)

RowType
PropertyFacet ::= (
false

DEFAULT defaultVal 

MULTIPLICITY   )
PropertyTypeFacet ::= 
MAXLENGTH | PRECISION | SCALE 

COLLATION

PRESERVESECONDS
PrimitiveType ::= 
BINARY | STRING | BOOLEAN

GUID

INT64

TIME
)
Facets用於描述屬性的元數據，如是否為可空、缺省值、為單值或多值。 










關係類型，如客戶和訂單是1對多關係。





**查詢物件**
ADO.NET 實體資料模型工具會產生從 ObjectContext (代表概念模型中所定義的實體容器) 衍生而來的類別。 ObjectContext 類別支援針對將實體當成物件傳回之概念模型進行查詢，也支援建立、更新和刪除實體物件。 Entity Framework 支援針對概念模型進行物件查詢。 這些查詢可以使用 Entity SQL 、Language-Integrated Query (LINQ) 和物件查詢產生器方法來撰寫。

**Entity SQL**
Entity Client 是 ADO.NET Entity Framework 中的原生用戶端 (Native Client)。它的物件模型和 ADO.NET 的其他用戶端非常相似，一樣有 Connection, Command, DataReader 等物件，但最大的差異就是，它有自己的 SQL 指令 (Entity SQL)，可以用 SQL 的方式存取 EDM。但沒有明確的joins。簡單的說，就是把 EDM 當成一個實體資料庫。
查詢管線分析Entity SQL查詢為一棵命令樹， query into a command tree, 分開多個表上的查詢，再移交EntityClient provider。EntityClient provider使用Connection對象初始化。EntityClient provider再把Entity SQL命令樹轉化為數據庫的本地SQL查詢。查詢返回Entity SQL ResultSet，但不限於一個表的結果。
// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
// Set the provider name.
entityBuilder.Provider = providerName;
// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;
// Set the Metadata location.
entityBuilder.Metadata =  @"res://*/AdventureWorksModel.csdl|
res://*/AdventureWorksModel.ssdl|
res://*/AdventureWorksModel.msl";
Console.WriteLine(entityBuilder.ToString());                                                                                                                     
using (EntityConnection conn = new EntityConnection(entityBuilder.ToString()))
{
conn.Open();
Console.WriteLine("Just testing the connection.");
conn.Close();
}

**Entity SQL經典函數**
Entity Framework兼容的data providers都支持的函數，可用於Entity SQL查詢。LINQ to Entities的大部門擴展方法都翻譯為經典函數。ADO.NET data provider會把經典函數翻譯為期望的SQL語句。 


**LINQ to Entities**
實作 IEnumerable 泛型介面或 IQueryable 泛型介面的資料來源可以透過 LINQ 進行查詢。 實作泛型 IQueryable 介面之泛型 ObjectQuery 類別的執行個體會當做 LINQ to Entities 查詢的資料來源。 ObjectQuery 泛型類別表示傳回零個或多個具型別物件之集合的查詢。 使用 C# 的 var 關鍵字 (在 Visual Basic 中為 Dim)，您也可以讓編譯器推斷實體類型。
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery products = AWEntities.Products;
// LINQ Query syntax:
IOrderedQueryable query =
from product in products
orderby product.Name, product.ListPrice descending
select product;
// LINQ Method syntax:
IOrderedQueryable query = products
.OrderBy(product => product.Name)
.ThenByDescending(product => product.ListPrice);
}

**查詢產生器方法**
ObjectQuery 類別支援對概念模型進行 LINQ to Entities 和 Entity SQL 查詢。 ObjectQuery 也會實作一組查詢產生器方法，這些方法可用來循序建構與 Entity SQL 相等的查詢命令。由於 ObjectQuery 會實作 IQueryable 和 IEnumerable，所以將 ObjectQuery 所實作的查詢產生器方法結合 LINQ 特定的標準查詢運算子方法 (如 First 或 Count) 是可行的。 LINQ 運算子並不會傳回 ObjectQuery，與查詢產生器方法不同。
// Get the contacts with the specified name.
ObjectQuery contactQuery = context.Contact
.Where("it.LastName = @ln AND it.FirstName = @fn",
new ObjectParameter("ln", lastName), 
new ObjectParameter("fn", firstName));

**開發工具**
目前 ADO.NET Entity Framework 的開發，在 Visual Studio 2008 中有充分的支援，在安裝 Visual Studio 2008 Service Pack 1 後，檔案範本中即會出現 ADO.NET 實體資料模型 (ADO.NET Entity Data Model) 可讓開發人員利用 Entity Model Designer 來設計 EDM，EDM 亦可由Windows記事本等文字編輯器所編輯。

**衍生服務**
微軟特別針對了網路上各種不同的應用程式（例如 AJAX，Silverlight，Mashup 應用程式）開發了一個基於 ADO.NET Entity Framework 之上的服務，稱為 ADO.NET Data Services（專案代號為 Astoria），並與 ADO.NET Entity Framework 一起包裝在 .NET Framework 3.5 Service Pack 1 中發表。

**支援廠商**
目前已有數個資料庫廠商或元件開發商宣佈要支援 ADO.NET Entity Framework:- Mircosoft,支持MsSQL.- Core Lab，支援Oracle、MySQL、PostgreSQL 與 SQLite 資料庫。- IBM，實作 DB2 使用的 LINQ Provider。- MySQL，發展 MySQL Server 所用的 Provider。- Npqsql，發展 PostgreSQL 所用的 Provider。- OpenLink Software，發展支援多種資料庫所用的 Provider。- Phoenix Software International，發展支援 SQLite 資料庫的 Provider。- Sybase，將支援 Anywhere 資料庫。- VistaDB Software，將支援 VistaDB 資料庫。- DataDirect Technologies，發展支援多種資料庫所用的 Provider。- Firebird，支援 Firebird 資料庫。

**參考資料**

**外部連結**
   MSDN Library : ADO.NET Entity Frameworkdate=20080828050120 -   讀寫 ADO.NET Entity Frameworkdate=20080908071404 -   整合 ADO.NET Entity Framework 到應用程式中date=20090120073403 -   首次接觸 ADO.NET Entity Frameworkdate=20081213005900 -   ADO.NET Entity Framework 概觀date=20081226101325 -   Recent ADO.NET Entity Framework provider news - Demos and downloads