什么是Entity Framework
在.NET 3.5之前烙肺,開發(fā)者通常使用ADO.NET獲取或保存數(shù)據(jù)到底層數(shù)據(jù)庫中氏堤。即通過ADO.NET連接到數(shù)據(jù)庫,然后使用DateSet對象與數(shù)據(jù)庫交互。這是一個麻煩且容易出錯的處理過程由桌,為了解決這個問題铭乾,微軟提供了Entity Framework的開源框架,處理程序與數(shù)據(jù)庫相關的操作。
EF是一個開源的ORM框架妇押,開發(fā)者使用DO(Domain Object)來處理數(shù)據(jù),而不需要關注數(shù)據(jù)庫中表和列。使用EF相對于傳統(tǒng)的應用程序,開發(fā)者可以用更少的代碼夫偶,在更高的層次處理數(shù)據(jù),以及創(chuàng)建和維護面向數(shù)據(jù)的應用卵佛。
官方定義
Entity Framework is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write.
EF是一個ORM,讓開發(fā)者使用.NET對象操作數(shù)據(jù)庫植捎。它解決了開發(fā)者需要編寫大量數(shù)據(jù)訪問代碼的疼點蚓峦。
下圖說明了EF在應用中的位置:
從上圖可知,EF在業(yè)務層(Domain classes)和數(shù)據(jù)庫之間一汽,它保存DO對象屬性中的數(shù)據(jù)避消,同時也能從數(shù)據(jù)庫中檢索數(shù)據(jù),然后自動轉換為DO對象召夹。
EF特征
- Cross-platform: EF Core 是跨平臺的框架岩喷,可以運行在Windows,Linux和Mac上监憎。
- 實體模型:EF創(chuàng)建一個基于POCO(普通CLR對象)對象的EDM(Entity Data Model 實體數(shù)據(jù)模型)纱意,使用這個模型可以查詢和保存實體數(shù)據(jù)到底層數(shù)據(jù)庫。
- 查詢:EF可以使用LINQ去獲取數(shù)據(jù)庫中的數(shù)據(jù)枫虏,database provider將轉換LINQ語句到特定的數(shù)據(jù)庫語言妇穴。EF也可使用原生的SQL語句爬虱。
- 變更跟蹤 Change Tracking:EF會跟蹤這個實體狀態(tài)的更改隶债。
- 保存 當調(diào)用SaveChanges()方法,EF會根據(jù)實體的變更執(zhí)行insert跑筝,update死讹,delete等命令。EF也提供了一個異步保存方法SaveChangeAsync()曲梗。
- 并發(fā):EF默認使用Optimistic Concurrency來保護其他用戶的變更覆蓋赞警。
- 事務:當查詢或保存數(shù)據(jù)時,EF自動執(zhí)行事務管理虏两。它也提供了自定義事務處理。
- 緩存:EF提供了緩存機制,所以间聊,重復的查詢將返回緩存中的數(shù)據(jù)淳玩,而不是去訪問數(shù)據(jù)庫。
- 配置:EF是可配置的祖凫,并包含了默認配置規(guī)則集合琼蚯,用戶可使用注釋特征或Fluent API去配置EF模型。
- 遷移:EF提供了遷移命令集合惠况,可在NuGet包管理器控制臺或CLI上遭庶,執(zhí)行創(chuàng)建或管理數(shù)據(jù)庫方案。
EF版本
微軟在2008年伴隨.NET Framework 3.5一起發(fā)布了EF稠屠。從哪以后峦睡,微軟又發(fā)布了很多的EF版本翎苫。到目前為止,最新的EF版本有兩個:EF 6 和 EF Core榨了。下表列舉了EF6和EF Core的不同之處:
EF6 | EF Core |
---|---|
2008年和.NET Framework 3.5一起發(fā)布 | 2016年與.NET Core 1.0 一起發(fā)布 |
穩(wěn)定拉队,功能多 | 新,且是EF的進化版 |
支持Windows | 跨平臺 |
工作在.NET Framework 3.5+ | .NET Framework 4.5+和.NET Core |
開源 | 開源 |
EF 6 的歷史版本
EF 版本 | 發(fā)布時間 | .NET Framework |
---|---|---|
EF 6 | 2013 | .NET 4.0&.NET 4.5,vs2012 |
EF 5 | 2012 | .NET 4.0,vs2012 |
EF 4.3 | 2011 | .NET 4.0,vs2012 |
EF 4 | 2010 | .NET 4.0,vs2010 |
EF 1 | 2008 | .NET 3.5 SP1,vs2008 |
EF Core 歷史版本
EF Core 版本 | 發(fā)布時間 | .NET Framework |
---|---|---|
EF Core 2.0 | 2017 8月 | .NET Core 2.0,vs2017 |
EF Core 1.1 | 2016 11月 | .NET Core 1.1 |
EF Core 1.0 | 2016 7月 | .NET Core 1.0 |
EF 基本工作流程
下圖說明了EF基本的CRUD工作流:
- 首先阻逮,定義模型粱快,包括領域類,context類(繼承自DbContext)叔扼,配置信息事哭。EF是基于這些模型對象執(zhí)行CRUD操作的。
- 插入數(shù)據(jù)時瓜富,添加領域對象到context中鳍咱,調(diào)用SaveChanges()方法,EF API會構建并執(zhí)行一個合適Insert語句与柑。
- 讀取數(shù)據(jù)時谤辜,執(zhí)行Linq-to-Entities查詢語句,EF API將其轉化為對應數(shù)據(jù)庫的SQL查詢語句并執(zhí)行它价捧,結果將轉化為DO對象丑念。
- 當context中更新或刪除對象時,調(diào)用SaveChanges()方法结蟋,EF API會構建并執(zhí)行合適的Update或Delete語句脯倚。
EF工作原理
EF API(EF 6 & EF Core)具有這些能力,包括:
- 將DO(領域模型對象)映射到數(shù)據(jù)庫集合
- 翻譯并執(zhí)行Linq語句
- 跟蹤實體在其生命周期變更嵌屎,以及保存實體的變更
EF API的首要任務是構建Entity Data Model(EDM)推正,EDM在內(nèi)存中的結構可以用來表示:概念模型,存儲模型以及者兩者兩者之間的映射宝惰。
Conceptual Model 概念模型由EF通過你定義的領域模型植榕,context和配置生成的。
Storage Model EF從數(shù)據(jù)庫集合中生成存儲模型尼夺。在code-first方案中尊残,存儲模型是由概念模型推斷出來的。在database-first方案中汞斧,它是從數(shù)據(jù)庫中推斷出來的夜郁。
Mappings 映射信息包含了概念模型和存儲模型之間的映射。
EF通過EDM執(zhí)行CRUD操作粘勒。它通過EDM從Linq語句中構建SQL竞端,以及將執(zhí)行結果轉變?yōu)閷嶓w對象。
EF 總體架構
下圖展示了EF的總體架構
我們分別看看架構中的組件
EDM(Entity Data Model):EDM由概念模型庙睡,映射和存儲模型三部分構成(見上文)事富。
Linq to Entities:L2E是一個針對對象模型編寫的查詢語言技俐,它返回定義在概念模型中的實體。
Entity SQL:Entity SQL是以一種查詢語言有點像L2E统台,但是只能運行在EF6中雕擂。相對于L2E,Entity SQL稍難贱勃,而且需要開發(fā)者單獨學習井赌。
Object Service:Object Service是訪問數(shù)據(jù)庫的主要入口點。它負責將下一層返回的數(shù)據(jù)轉換為實體對象的結構贵扰。
Entity Client Data Provider:這一次主要負責將Linq語句轉化為數(shù)據(jù)的SQL語句仇穗,它與ADO.Net進行通信,ADO.Net又向數(shù)據(jù)庫發(fā)送或檢索數(shù)據(jù)戚绕。
ADO.Net Data Provider:這一層使用標準的ADO.Net庫與數(shù)據(jù)庫通訊纹坐。
Context類
在EF中context非常重要,它類繼承自DbContext舞丛,它表示一個與數(shù)據(jù)庫的會話耘子。下面的代碼是context類的示例:
public class SchoolContext:DbConext{
public SchoolContext(){
}
public DbSet<Student> Students {get;set;}
public DbSet<StudentAddress> StudentAddresses {get;set;}
public DbSet<Grade> Grades {get;set;}
}
上面的示例中,SchoolContext繼承自DbContext球切,使得他成為了一個context類谷誓。它包含了Student,StudentAddress以及Grade的實體集合欧聘。
context類用于從數(shù)據(jù)庫中查詢或保存數(shù)據(jù)片林。也可以用來配置領域模型端盆,數(shù)據(jù)庫關系映射怀骤,變更追蹤變更設置,緩存焕妙,事務等蒋伦。
EF中的實體
EF中的實體是應用程序的領域類,他被包含在context類的DbSet<TEntity>類型屬性中焚鹊。EF API將TEntity映射到數(shù)據(jù)庫中的表痕届,TEntity的屬性映射為表中的列。比如末患,在school應用程序中研叫,Student,StudentAddress和Grade的領域模型如下:
public class Student{
public int StudentID {get;set;}
public string StudentName {get;set;}
public DateTime? DateOfBirth {get;set;}
public byte[] Photo {get;set;}
public decimal Height {get; set}
public float Weight {get; set}
//引用導航屬性
public StudentAddress StudentAddress {get; set;}
public Grade Grade {get; set;}
}
public partial class StudentAddress{
public int StudentID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
//引用導航屬性
public Student Student { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
//集合導航屬性
public ICollection<Student> Students { get; set; }
}
當他們包含在context類中的DbSet<TEntity>屬性中時璧针,它們就是實體嚷炉。而Students, StudentAddresses和Grades被稱為實體集。
實體包含兩種類型的屬性:標量屬性(Scalar Properties)和導航屬性(Navigation Properties)探橱∩暌伲基本類型的屬性稱為標量屬性绘证,標量屬性存儲實際的數(shù)據(jù),標量屬性映射到數(shù)據(jù)中表的列哗讥。導航屬性表示該屬性關聯(lián)到另一個實體嚷那,這里又有兩種類型的導航屬性:引用導航和集合導航。
- 引用導航屬性表示杆煞,一個實體的屬性的類型是另一個實體類型魏宽。
- 集合導航屬性表示,實體屬性的類型是集合類型决乎。
EF中實體的類型
EF中有兩種實體類型:POCO實體和動態(tài)代理實體(Dynamic Proxy Entity)湖员。
- POCO實體:POCO就是一個基本類,不依賴任何框架瑞驱,EF 6和EF Core都支持POCO實體娘摔。POCO實體通過EDM生成實體類型,支持CRUD操作唤反。
- 動態(tài)代理(POCO Proxy)是運行時的代理類凳寺,它包裹了POCO實體,動態(tài)代理實體可以lazy loading彤侍。動態(tài)代理類只支持EF6(EF Core 2.0 不支持該類型)肠缨。
實體的狀態(tài)
EF API維護實體的狀態(tài)。context類執(zhí)行實體操作時盏阶,會影響實體的狀態(tài)晒奕。實體的狀態(tài)用枚舉來表示,EF 6中是System.Data.Entity.EntityState枚舉類型名斟,而EF Core中是Microsoft.EntityFrameworkCore.EntityState枚舉類型脑慧。他們有如下的枚舉值:
- Added 執(zhí)行insert命令
- Modified 執(zhí)行update命令
- Deleted 執(zhí)行delete命令
- Unchanged 無任何改變
- Detached 不追蹤實體的狀態(tài)
context不僅保存所有實體的引用(從數(shù)據(jù)庫中獲取)砰盐,而且還能追蹤和維護實體的狀態(tài)(這個功能叫變更追蹤)闷袒。context僅會自動處理實體從Unchanged狀態(tài)到Modified狀態(tài)。其他狀態(tài)的改變必須使用明確的DbContext或DbSet方法岩梳。在調(diào)用context.SaveChanges()方法時囊骤,EF API是基于實體的state創(chuàng)建和執(zhí)行增刪改語句的。
開發(fā)模式
EF有三種不同的模式供開發(fā)者選擇:
- Database-First
- Code-First
- Model-First
在數(shù)據(jù)庫優(yōu)先模式中冀值,可以使用Visual Studio集成EDM向導或執(zhí)行EF命令來存在的數(shù)據(jù)庫生成context和實體也物。EF 6對該中模式支持的非常好,EF Core也提供了有限的支持列疗。
當應用程序還沒有數(shù)據(jù)庫時滑蚯,可以使用代碼優(yōu)先模式。在這種模式下作彤,需要先寫DO和context膘魄,然后使用遷移命令創(chuàng)建數(shù)據(jù)庫乌逐。開發(fā)者如果遵循領域驅動設計(Domain-Driven Design DDD)原則,喜歡先編寫領域模型然后在生成數(shù)據(jù)庫创葡。EF 6和EF Core都支持這種模式浙踢。
模型優(yōu)先模式下,Visual Studio中集成了的Visual Designer工具灿渴,可以在上面創(chuàng)建實體洛波,關系和繼承層次結構,然后生成實體骚露,context和數(shù)據(jù)庫腳本蹬挤。這種方式僅EF 6支持。
EF中的持久方式
當使用EF保存實體到數(shù)據(jù)庫中時棘幸,有兩種場景供選擇:連接場景和非連接場景焰扳。
連接場景
在連接場景下,檢索和保存實體都是使用的同一個context對象误续,這樣吨悍,它可以在對象的生命周期中保持對其狀態(tài)的追蹤。這種場景常常用在Windows應用程序或數(shù)據(jù)庫在本地的情況蹋嵌。
上圖可以看到育瓜,檢索和保存都是使用的同一個context對象。這項做的好處是栽烂,執(zhí)行效率高躏仇,context對象保持對實體狀態(tài)的跟蹤。缺點是需要對數(shù)據(jù)庫保持長連接腺办,比較耗資源焰手。
非連接場景
檢索和保存使用不同的context對象,使用完后context對象會被自動釋放菇晃。
非連接場景要相對復雜些册倒,因為context對象不能追蹤實體的狀態(tài),所以開發(fā)者在調(diào)用SaveChanges()方法前磺送,必須要設置實體的狀態(tài)。在上圖中灿意,程序使用context1檢索數(shù)據(jù)估灿,使用context2執(zhí)行CUD操作。這種模式常用在web應用程序或遠程數(shù)據(jù)庫的情況缤剧。優(yōu)點馅袁,使用較少的資源,不需要長連接荒辕。缺點汗销,在保存數(shù)據(jù)之前需要設置實體的狀態(tài)犹褒,執(zhí)行效率稍慢。