本篇目錄
- Entity Framework概要
- 什么是ORM
- Entity Framework簡史
- Entity Framework具有的能力
- Entity Framework的架構
- Entity Framework建模和持久化
- Entity Framework的三種開發風格
- 如何選擇持久化方法
- 本章小結
- 自我測試
Entity Framework概要
Entity Framework是微軟的Object Relational Mapper(對象關系映射器),也就是我們平常說的ORM,它可以讓應用程序開發者將關系型數據作為業務模型來使用,也消除了開發者為數據訪問編寫的絕大多數管道代碼的需要(比如使用ADO.NET)。Entity Framework提供了一個綜合的、基於模型的系統,通過擺脫為所有的領域模型編寫相似的數據訪問代碼,使得開發者創建數據訪問層是如此之簡單。Entity Framework的首發版本是EF3.5,是伴隨着.Net Framework 3.5 SP1和VS 2008 SP1一同發布的。從那之后,EF已經進化了很多很多,當前版本是6.1.3
Entity Framework通過開啟數據訪問和將數據表示為概念化模型(即一系列的實體類和關系)減輕了創建數據訪問層的任務。應用程序可以執行基本的CRUD操作,以及輕松地管理實體間的一對一,一對多和多對多關系。
下面是使用Entity Framework的一些好處:
- 因為開發者不需要為數據訪問編寫所有需要的ADO.NET管道代碼,因此這可以節省很多開發時間。
- 我們可以使用更高級的語言(例如C#)來編寫所有的數據訪問邏輯而不是編寫SQL查詢和存儲過程。
- 因為數據庫表沒有高級的關系(如繼承),然而領域實體是可以有的,所以業務模型(也就是概念模型)可以使用實體間的關系來適配應用領域。
- 底層的數據存儲可以相對輕松地被取代,因為所有的數據訪問邏輯都呈現在應用層而不是數據層。
現在通過一張圖看一下EF的架構:
從這張圖上可以看到,EF是建立在ADO.NET框架之上的,它下面仍舊使用了ADO.NET方法和類來執行數據操作。
什么是ORM
幾乎所有的商業軟件都要存儲數據,多年來,Relational Database Management System(RDBMS)一直是開發者尋求的數據存儲。ORM是允許開發者使用面向對象的編程語言訪問RDBMS數據的一系列技術。可用的RDBMS包括SQL Server, Oracle, DB2, MySQL等等。這些數據庫系統有一些共性。每個數據庫系統都支持一個或多個數據庫。數據庫都包含數據表,每個表都以表格的形式存儲數據,並且被分成了列和行。多個表中的數據行可能相互關聯。比如,一個訂單Order表中的Id可能存儲在一個流水表Transaction中。
過去,在像EF這樣的工具出現之前,開發者都是在軟件代碼內部嵌套的sql語句,這是因為編程語言不能原生理解Sql。比如,要從數據庫中檢索數據,然后將結果作為對象操作,必須使用ADO.NET要寫相當數量的代碼才行。具體來說,先定義一個存儲person的類,然后打開數據庫連接,創建具有查詢文本的命令,再執行該命令的reader,然后對該reader的結果進行迭代,最后再使用來自reader的數據填充Person類的實例。你會看到,這里包含了很多步驟,而且更重要的是,這樣寫的代碼維護成本很高。比如,數據庫中改了一個列名,這樣還要去代碼中進行相應更改,否則運行時就會拋出異常。此外,我們數據庫中存儲的是標量值數據(int,string等),但我們的目標是一個對象或者對象圖。這樣看來,這種訪問數據的方式有很多問題。
首先,RDBMS的列類型和.Net類型之間有類型失配;其次,存儲和目標之間也不匹配,前者是標量值的集合,后者是具有屬性的對象。更糟糕的是,鍵入我們的person對象有一個更復雜的屬性List
ORM這些工具出現的原因就是為了解決這種失配問題。ORM工具將存儲在數據表中的數據表示為對象,這比起傳統的代碼有很多優勢:
它們使用原生.net類型暴露數據,使用簡單的屬性暴露相關的數據,提供編譯時檢查。
最后,在后面會看到,你會寫更少的代碼。更少的代碼意味着更少的bugs,不是嗎?:)
Entity Framework簡史
多年來,有許多ORM工具進入市場,有開源的,也有商業的。微軟也開發了自己的ORM工具。第一個是內置於.Net 3.5的LINQ to SQL。該ORM僅支持
SQL Server和SQL Server Compact。2008年第一次發布的Entity Framework是第二次嘗試,相較於LINQ to SQL有很多優點。首先,有自己的provider架構,因此對於所有的關系數據庫引擎都是開放的,而不僅僅是SQL Server。現在所有的主要RDBMS都有Entity Framework provider。
Entity Framework經歷了很多版本。
第一版只支持Database First。這意味着你要將設計器指向一個已存在的數據庫,然后就會生成一個包含數據庫和表抽象的代碼。除了代碼之外,還會創建一個EDMX文件,該XML文件包含了實體數據模型(因此你也就知道了EDMX的意思了Entity Data Model Xml)。它包括三個模型:邏輯,存儲和映射。邏輯模型(有時也叫概念模型)就是使用C#進行編碼的那個,存儲模型描述了數據是如何存儲到數據庫中的,映射模型提供了邏輯模型和存儲模型之間的映射。如果你在數據庫中更改了東西,那么你也要更新生成的模型,C#代碼也要再次生成。映射模型有一個基於ObjectContext
的類,該類有數據庫中每張表的集合屬性,每個集合都是一個泛型集合,集合中的元素類型是從EF中的一個基類中繼承的。每個類都有屬性和相應的數據表中的列對應。
第二版,也就是EF4,也開始支持Model-First了。這樣 ,我們就可以使用設計面板創建實體類,然后設計器會產成SQL腳本來生成數據庫。對於這種方法,仍會生成EDMX文件,最終的結果是和Database First是相同的。
最后,EF的Code First在版本4.1中引入。Code First不需要EDMX文件了,每個實體也不需要從EF的基類中繼承了。這樣,代碼變得更加容易測試。這種方法也不需要依賴設計器了,你只需要編寫類就行,而且它們會自動地映射到數據庫中的表。當前的EF 6.1.3中的Code First已經相當強大了。
Entity Framework具有的能力
EF對於微軟開發者可以做很多事情。
首先,它可以將數據庫暴露成對象的集合,這是通過利用很多關鍵的類完成的。前提是你要了解DbContext
,這個類是EF Code First的核心,在高層次上是數據庫抽象。數據庫包含了表,每個表又包含了行和列。DbContext有泛型集合屬性,每個屬性的類型是DbSet<TRowType>
對應於每個表。集合中的每個對象指的是一個實體,代表相應表中的一行。數據表中的列是定義在TRowType
類中的屬性。
一旦這個結構布局好了,那么你就能夠通過LINQ查詢來查詢底層的數據庫了。如果你將一個全新的TRowType
類的實例添加到父集合中,然后使用DbContext API保存更改,那么這個新的對象就會變成相應表中的一行,該對象的每個屬性的值就會變成該行相應的列值。此外,EF有能力表示其他的數據庫工件,比如存儲過程和函數。數據庫結構的進化是很重要的一個問題,在大多數情況,隨着應用程序的變化,你需要添加列和表,EF是通過Migration(遷移)功能來解決這個問題的。這個能力允許你通過C#代碼更改數據庫結構,除了添加和刪除表和列之外,還可以添加索引。Migration可以沒有數據損失地進化數據庫模式。你將會看到,EF會暴露你需要使用C#訪問的一切數據而不需要編寫SQL,並且像對待你整個應用程序代碼的一部分來對待數據庫。你可以將migration代碼遷入到源代碼控制系統(Git/SVN)中,因為它也是C#代碼!
Entity Framework的架構
EF構建在provider架構之上。當開發者使用C#創建一個LINQ查詢時,EF框架引擎會連接一個provider,將它轉換成實際的SQL語句,最后發往數據庫。任何給定的provider都是連接Entity Framework和一個特定的RDBMS的橋梁。一旦該provider執行了最終的SQL命令,結果就被EF物質化到.NET對象中。Data reader就是為了這個目的。理解EF構建於ADO.NET之上非常重要,因此,EF也使用了諸如connection,command,和data reader的概念。談到數據持久化,也就是插入,更新和刪除功能,插入時,開發者將一個實體類的實例添加到數據庫上下文中。相似地,之前添加到上下文中的實例被標記為changed或deleted,就會產生對數據庫即將執行更新和刪除的語句。EF會檢查上下文中的每個對象,再次使用provider來創建RDBMS特定的insert,update,或delete命令。
Entity Framework建模和持久化
EF依賴概念模型完成工作,首先來理解一下什么是Entity Data Model(EDM)以及EF如何使用它管理數據庫操作。
理解EDM
概念數據模型是EF的核心。要使用EF,我們必須創建概念數據模型,即EDM。EDM定義了我們的概念模型類,這些類之間的關系,以及這些模型到數據庫模式之間的映射。
一旦創建了EDM,我們就可以對概念模型執行所有的CRUD操作,EF會將所有的這些對象查詢翻譯成數據庫查詢(SQL)。一旦這些查詢執行了,EF就會將返回的結果轉成概念模型對象實例。EF會使用存儲在EDM中的映射信息來執行對象查詢到SQL查詢,以及相關的數據到概念模型的翻譯。
一旦EDM准備就緒,我們就可以使用模型對象來執行CRUD操作。要能夠執行CRUD操作,我們必須使用ObjectContext
類。接下來讓我們理解一下這個類。
理解ObjectContext類
一旦我創建了EDM,我就有了應用程序中可以使用的所有的實體。然而,我還需要一個東西來讓我在這些實體上執行各種操作。它就是EF中的ObjectContext
類。
ObjectContext
類是EF中的主要對象。它負責:
- 管理數據庫連接
- 提供執行CRUD操作的支持
- 追蹤模型的更改,目的在於在數據庫中更新模型
ObjectContext
類可以理解成管理EDM中所有實體的東西,讓我們為這些實體執行所有的數據庫操作。當我們想要保存一個新的或者更改的對象到數據庫時,我們必須調用ObjectContext
類中的SaveChanges
方法。
還有另一個類
DbContext
,它和ObjectContext
類很相似。實際上,Dbcontext
類就是ObjectContext
類的封裝類。它是一個更新的API,而且它提供了更好的API來管理數據庫連接和執行CRUD操作。
因為DbContext是更好的API,所以我們會使用DbContext
來執行所有的數據庫操作。
Entity Framework的三種開發風格
- Database First:這是一種用於已存在數據庫模式的方法。使用這種方法,EDM是從數據庫模式中生成的,這種方法最適合於使用了已經存在的數據庫的應用。
- Code First:這種方法中,所有的領域模型都是以類的形式編寫的。這些類會建立我們的EDM,數據庫模式會從這些類中創建。這種方法最適合於那些高度以領域為中心並且領域模型類創建優先的應用程序。這里需要的數據庫只是為了這些領域模型的持久化機制。
- Model First:這種方法和Code First方法很相似,但是這種情況下我們使用了EDM視覺設計器來設計我們的模型。數據庫模式和類將會通過這個概念模型生成。該模型將會給我們創建數據庫的SQL語句,然后我們可以使用它來創建數據庫並連接應用程序。
三種風格的比較
Database First
主要的好處就是:如果數據庫已經存在了,那么只需要花一點時間就可以編寫數據訪問層。EDM可以從數據庫中生成,然后根據需求更改EDM。
一些場景:
- 對遺留的數據庫進行開發
- 當其他團隊的DBA完成了數據庫設計時,一旦數據庫完成,應用開發就要開始
- 當要開發數據為中心的應用時,應用領域模型就是數據庫本身,數據庫會頻繁修改來滿足新的需求。
Model First
和Database First相似,Model First最終以EDM結束。使用該EDM,我們可以創建概念模型和數據庫。使用這種方法的唯一原因就是我們真的想要使用視覺實體設計器。
Code First
Code First對於所有的業務邏輯以類實現,並且數據庫只用作這些模型的持久化機制時很有用。
選擇Code First的一些原因:
- 數據庫只是作為模型的持久化機制,即數據庫中沒有邏輯。
- 完全控制代碼,即沒有自動生成的模型和上下文代碼。
- 數據庫不會手動更改。模型類總是更改,然后數據庫基於模型類的更改而更改。
如何選擇持久化方法
上面介紹了三種選擇,至於選擇哪一種,這也是個不大不小的問題,那么請參考下面進行決定:
方法一:工作流決定樹
方法二:檢查清單
場景 | 方式 |
---|---|
有遺留的數據庫或者數據庫已經存在 | Database First |
在開始開發前,我們會獲得DBA創建的數據庫 | Database First |
數據庫頻繁改變,應用程序應該隨之改變 | Database First |
我們想要使用視覺實體設計器來生成數據庫和模型類 | Model First |
我們已有模型類並且只需要數據庫保存數據 | Code First |
我們想要編寫所有的模型類,實現這些類,然后考慮數據庫存儲 | Code First |
我們不想處理自動生成的類,且更喜歡動手親自編寫 | Code First |
本章小結
這一節我們看到了傳統的嵌入式sql訪問數據的短處,並理解了什么是ORM以及ORM主要解決的問題。同時,我們回顧了一下Entity Framework的歷史發展,也看到EF能做什么。我們也簡要地看了一下EF的架構。然后理解了什么EDM,ObjectContext,以及它和DbContext的區別和聯系。隨后我們介紹了EF的三種開發方式(也叫EF工作流)和它們之間的比較,以及使用它們的可能場景,最后介紹了如何選擇哪一種方式。
自我測試
-
ORM工具解決了下面問題中的哪一個?
- RDBMS和.Net Framework類型是相同的。
- RDBMS和OOP之間的阻抗失配
- 學習SQL很困難
-
在EF中開發者必須編寫SQL查詢,對嗎?
-
EF使用了哪種技術來將結構的變化應用到數據庫中?
- Updates
- Conversions
- Migrations
-
使用EF Code First時,下面哪個重要的類代表了數據庫的抽象?
- DbContext
- ObjectContext
- DataContext
-
EF只能使用微軟數據庫工作,如SQL Server,對嗎?
點擊查看答案默認您已支持本文
參考書籍:
《Mastering Entity Framework》
《Code-First Development with Entity Framework》
《Programming Entity Framework Code First》