实体框架(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 数据库。