實體框架(Entity Framework)簡介
簡稱EF
與ADO.NET關系
ADO.NET Entity Framework 是微軟以 ADO.NET 為基礎所發展出來的對象關系對應 (O/R Mapping) 解決方案,早期被稱為 ObjectSpace,最新版本是EF7【CodeOnly功能得到了更好的支持】
實體框架Entity Framework 是 ADO.NET 中的一組支持開發面向數據的軟件應用程序的技術。是微軟的一個ORM框架。
什么是O/R Mapping
廣義上,ORM指的是面向對象的對象模型和關系型數據庫的數據結構之間的相互轉換。
狹義上,ORM可以被認為是,基於關系型數據庫的數據存儲,實現一個虛擬的面向對象的數據訪問接口。理想情況下,基於這樣一個面向對象的接口,持久化一個OO對象應該不需要要了解任何關系型數據庫存儲數據的實現細節。
ORM in EF
Entity Framework 利用了抽象化數據結構的方式,將每個數據庫對象都轉換成應用程序對象 (entity),而數據字段都轉換為屬性 (property),關系則轉換為結合屬性 (association),讓數據庫的 E/R 模型完全的轉成對象模型,如此讓程序設計師能用最熟悉的編程語言來調用訪問。而在抽象化的結構之下,則是高度集成與對應結構的概念層、對應層和儲存層,以 及支持 Entity Framework 的數據提供者 (provider),讓數據訪問的工作得以順利與完整的進行。
(1) 概念層:負責向上的對象與屬性顯露與訪問。
(2) 對應層:將上方的概念層和底下的儲存層的數據結構對應在一起。
(3) 儲存層:依不同數據庫與數據結構,而顯露出實體的數據結構體,和 Provider 一起,負責實際對數據庫的訪問和 SQL 的產生。
EDM 設計器
EF Demo演示
一、數據庫優先的方式
1、創建控制台項目
2、創建數據庫(添加表)
CREATE TABLE [dbo].[T_Customer]( [Id] [int] IDENTITY(1,1) NOT NULL, [UserName] [nvarchar](32) NULL, [Age] [int] NULL, [Address] [nvarchar](64) NULL, CONSTRAINT [PK_T_Customer] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
3、 在項目中添加“數據實體模型”
點擊下一步,選擇“從數據庫生成”
新建數據庫連接,
在代碼中添加訪問上下文保存到數據庫的代碼
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFDemo { class Program { static void Main(string[] args) { DemoSiteEntities entity = new DemoSiteEntities(); T_Customer customer = new T_Customer { Address="東海五彩金輪",Age=27,UserName="楚留香"}; entity.T_Customer.Add(customer); //這里只相當於構造sql語句 entity.SaveChanges(); //這里才進行數據庫操作,相當於按F5執行 } } }
執行后,我們來看下數據庫中,已經插入了一條數據
發散思維:如果讓你實現一個ORM框架!
在EF中的實體數據模型(EDM)由以下三種模型和具有相應文件擴展名的映射文件進行定義。
· 概念架構定義語言文件 (.csdl) -- 定義概念模型。
· 存儲架構定義語言文件 (.ssdl) -- 定義存儲模型
· 映射規范語言文件 (.msl) -- 定義存儲模型與概念模型之間的映射M。
實體框架 使用這些基於 XML 的模型和映射文件將對概念模型中的實體和關系的創建、讀取、更新和刪除操作轉換為數據源中的等效操作。EDM 甚至支持將概念模型中的實體映射到數據源中的存儲過程。
EF中操作數據庫的網關
ObjectContext封裝 .NET Framework 和數據庫之間的連接。此類用作“創建”、“讀取”、“更新”和“刪除”操作的網關。
ObjectContext 類為主類,用於與作為對象(這些對象為 EDM 中定義的實體類型的實例)的數據進行交互。
ObjectContext 類的實例封裝以下內容:
到數據庫的連接,以 EntityConnection 對象的形式封裝。
描述該模型的元數據,以 MetadataWorkspace 對象的形式封裝
用於管理緩存中持久保存的對象的 ObjectStateManager 對象
IQueryable接口與IEnumberable區別
IQueryable接口與IEnumberable接口的區別: IEnumerable<T> 泛型類在調用自己的SKip 和 Take 等擴展方法之前數據就已經加載在本地內存里了,而IQueryable<T> 是將Skip ,take 這些方法表達式翻譯成T-SQL語句之后再向SQL服務器發送命令。也是延遲在我要真正顯示數據的時候才執行。
linq to ef中使用Ienumberable與Iqueryable的區別,要用到的SQL Server Profiler工具
Linq To EF
數據庫,這里還是使用northwnd.mdf了,下載地址:http://files.cnblogs.com/files/jiekzou/northwnd.zip
簡單查詢:
var result = from c in Entities.Customer select c;
條件查詢:
普通linq寫法:
var result = from c in Entities.Customer where c.Gender ==‘w’ select c;
Lambda表達式寫法:
var result = Entities.Customer.Where<Customer>(c =>c.Gender==‘w’);
排序分頁寫法:
IQueryable<Customers> cust10 = (from c in customers orderby c.CustomerID select c).Skip(0).Take(10);
左外連接:可以的連接有Join 和 GroupJoin 方法。GroupJoin組聯接等效於左外部聯接,它返回第一個(左側)數據源的每個元素(即使其他數據源中沒有關聯元素)。
var query = from d in edm.Order_Details join order in edm.Orders on d.OrderID equals order.OrderID select new { OrderId = order.OrderID, ProductId = d.ProductID, UnitPrice = d.UnitPrice };
排序分頁:
IQueryable<Customers> cust10 = (from c in customers orderby c.CustomerID select c).Skip(0).Take(10);
聚合
可使用的聚合運算符有Average、Count、Max、Min 和 Sum。
using (var edm = new NorthwindEntities()) { var maxuprice = edm.Products.Max(p => p.UnitPrice); Console.WriteLine(maxuprice.Value); }
連接
可以的連接有Join 和 GroupJoin 方法。GroupJoin組聯接等效於左外部聯接,它返回第一個(左側)數據源的每個元素(即使其他數據源中沒有關聯元素)。
using (var edm = new NorthwindEntities()) { var query = from d in edm.Order_Details join order in edm.Orders on d.OrderID equals order.OrderID select new { OrderId = order.OrderID, ProductId = d.ProductID, UnitPrice = d.UnitPrice }; foreach (var q in query) Console.WriteLine("{0},{1},{2}",q.OrderId,q.ProductId,q.UnitPrice); }
不支持在查詢中引用非標量閉包(如實體)。在執行這類查詢時,會引發 NotSupportedException 異常,並顯示消息“無法創建類型為“結束類型”的常量值。此上下文中僅支持基元類型(‘如 Int32、String 和 Guid’)
如下將會報異常的代碼:
using (var edm = new NorthwindEntities()) { Customers customer = edm.Customers.FirstOrDefault(); IQueryable<string> cc = from c in edm.Customers where c == customer select c.ContactName; foreach (string name in cc) Console.WriteLine(name); }
上面的代碼中,由於customer是引用類型而不是Int32,String,Guid的標量類型,所以在執行到where c==customer這個地方時,會報異常。
var query = from c in db.Categories join p in db.Products on c.CategoryID equals p.CategoryID group new {c, p} by new {c.CategoryName} into g select new { g.Key.CategoryName, SumPrice = (decimal?)g.Sum(pt=>pt.p.UnitPrice), Count = g.Select(x=>x.c.CategoryID).Distinct().Count() };
延遲加載
延遲加載:又稱作懶加載。也就是Linq To EF並不是直接將數據查詢出來,而是要用到具體數據的時候才會加載到內存
Include是將關聯實體一塊加載
ToList等可以直接將數據加載到內存
使用機制的選擇
關於上下文使用注意事項
- 不同的上下文實例來直接控制對應的實體
- 實體只能由一個上下文跟蹤管理
- EF上下文的ObjectStateMagner管理實體
- 批量操作時提交數據庫的選擇
- 延遲加載機制的選擇
- 查詢Distinct的使用數據量大小適時的選擇是在內存中操作還是在數據庫中操作
EF 跨數據庫支持
目前已有數個數據庫廠商或元件開發商宣布要支持 ADO.NET Entity Framework:
(1) Core Lab,支持Oracle、MySQL、PostgreSQL 與 SQLite 數據庫。
(2) IBM,實現 DB2 使用的 LINQ Provider。
(3) MySQL,發展 MySQL Server 所用的 Provider。
(4) Npqsql,發展 PostgreSQL 所用的 Provider。
(5) OpenLink Software,發展支持多種數據庫所用的 Provider。
(6) Phoenix Software International,發展支持 SQLite 數據庫的 Provider。
(7) Sybase,將支持 Anywhere 數據庫。
(8) VistaDB Software,將支持 VistaDB 數據庫。
(9) DataDirect Technologies,發展支持多種數據庫所用的 Provider。
(10) Firebird,支持 Firebird 數據庫。