Entity Framework的原理及使用方式

ADO.NET Entity Framework操作数据库的过程对用户是透明的(当然我们可以通过一些工具或方法了解发送到数据库的SQL语句等)。我们唯一能做的是操作EDM,EDM会将这个操作请求发往数据库。

Entity Framework实现了一套类似于ADO.NET2.0中连接类(它们使用方式相同,均基于Provider模式)的被称作EntityClient的类用来操作EDM。ADO.NET2.0的连接类是向数据库发送SQL命令操作表或视图,而EntityClient是向EDM发送EntitySQL操作Entity。EntityClient在EntityFramework中的作用是相当重要的,所有发往EDM的操作都是经过EntityClient,包括使用LINQ to Entity进行的操作。

各种使用方式总结

上文提到对EDM的操作,首先通过一个图来展现一下目前我们可用的操作的EDM的方式:

这几种访问方式使用介绍如下:(部分示例代码来源MSDN Magzine)

  1. EntityClient+EntitySQL

    示例代码:

string city = "London";

using (EntityConnection cn = new EntityConnection("Name=Entities"))

{

cn.Open();

EntityCommand cmd = cn.CreateCommand();

cmd.CommandText = @"SELECT VALUE c FROM Entities.Customers AS c WHERE

c.Address.City = @city";

cmd.Parameters.AddWithValue("city", city);

DbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

while (rdr.Read())

Console.WriteLine(rdr["CompanyName"].ToString());

rdr.Close();

}

  1. ObjectService+EntitySQL

在有EntityClient+EntitySQL这种使用方式下,使用ObjectService+EntitySQL的方式是多此一举,不会得到任何编辑时或运行时的好处。在ObjectContext下使用EntitySQL的真正作用是将其与LINQ to Entity结合使用。具体可见下文所示。

示例代码:

string city = "London";

using (Entities entities = new Entities())

{

ObjectQuery<Customers> query = entities.CreateQuery<Customers>(

"SELECT VALUE c FROM Customers AS c WHERE c.Address.City = @city",

new ObjectParameter("city", city)

);

foreach (Customers c in query)

Console.WriteLine(c.CompanyName);

}

  1. ObjectContext+LINQ( to Entity)

    方式一:

string city = "London";

using (Entities entities = new Entities())

{

var query = from c in entities.Customers

where c.Address.City == city

select c;

foreach (Customers c in query)

? Console.WriteLine(c.CompanyName);

}

方式二:

string city = "London";

using (Entities entities = new Entities())

{

var query = entities.Customers.Where(r => r.Address.City == city);

foreach (Customers c in query)

? Console.WriteLine(c.CompanyName);

}

这两段示例代码中的entities.Customer的写法隐式调用了2中示例的ObjectQuery<Customers>来进行查询(关于此可以参见EDM的设计器文件-xxx.designer.cs)。在方式二中的Where方法传入的是一个Lambda表达式,你也可以传入一条EntitySQL语句做参数来将LINQ与EntitySQL结合使用。如下代码演示其使用:

string city = "London";

using (Entities entities = new Entities())

{

var query = entities.Customers.Where("r.Address.City = ‘"+city+"‘");

foreach (Customers c in query)

? Console.WriteLine(c.CompanyName);

}

使用技巧及需要注意的问题

这也是上文提到的在ObjectContext下使用EntitySQL的一个主要作用,上面的例子比较简单可能看不到这样使用的优势,但是如下两种情况下使用EntitySQL可能是最好的选择。

  1. 动态构建查询条件 当查询条件的个数固定时,我们也可以采用罗列多个Where扩展方法的形式,如下:


    ObjectQuery.Where(LambdaExpression1) .Where(LambdaExpression2)…

    但是当这个条件的存在与否需要在运行时判断时,我们只能通过组合字符串来得到这个条件,我们可以将条件组合为EntitySQL并传递给Where()方法。

  2. 数据库模糊查询

    下面代码演示使用EntitySQL的like完成模糊查询:


context.Customer.Where("it.CustomerID LIKE @CustomerID", new System.Data.Objects.ObjectParameter("CustomerID","%V%"));

这个并不是只能使用EntitySQL来实现,LINQ to Entity也可以很容易完成。如下代码:


context.Customer.Where(r => r.CustomerID.Contains("V"));

同理,"V%"、"%V"可以分别使用StartsWith()与EndsWith()函数实现。

使用LINQ to Entity需要注意的一个方面是,在完成查询得到需要的结果后使用ToList或ToArray方法将结果转变为内存中的对象,然后使用LINQ to Objects来处理,否则处在Entity Framework的联机模式下对性能有很大的影响。

几种方法的性能分析及使用选择

首先用下图来说明一个执行过程。

图中所示表达的意思已经非常清楚,稍加解释的是,无论是通过EntityClient直接提供给Entity Client Data Provider的Entity SQL还是通过ObjectService传递的Entity SQL(或是LINQ to Entity),都在Entity Client Data Provider中被解释为相应的Command Tree,并进一步解释为对应数据库的SQL。这样来看使用LINQ to Entity与Entity SQL的效率应该差不多,但是还有一个问题,那就是EntitySQL所转换的最终SQL可能要比LINQ to Entity生成的SQL效率高,这在一定程度上使两者效率差增大,但是LINQ to Entity有其它技术无法比拟的好处,那就是它的强类型特性,编辑时智能感知提醒,编译时发现错误,这都是在一个大型项目中所需要的。虽然现在也有了调试EntitySQL的工具,但其与强类型的LINQ to Entity还是有很大差距。

另外在ObjectService与直接使用EntityClient问题的选择上。如果你想更灵活的控制查询过程,或者进行临时查询建议选择EntityCLient,如果是操作数据那只能采用ObjectService。

上文总结了各种操作EDM的方式,下面引用MSDN的一个对这几种技术进行比较的表格:

 
EntityClient 和实体 SQL


对象服务和实体 SQL


对象服务和 LINQ


定向到 EntityClient 提供程序





适合临时查询





可直接发出 DML





强类型化





可将实体作为结果返回




通过这个表可以很好对某一场合下应该选择的技术进行判断。EntityClient 和实体 SQL可以进行最大的控制,而使用LINQ to Entity可以获得最佳的编辑时支持。

其它操作EDM的方式

通过EdmGen更灵活的控制EDM

在.NET Framework 3.5的文件夹下有一个名为EdmGen的工具,Visual Studio的实体设计器就是调用这个工具来完成EDM的生成等操作。通过直接使用这个工具的命令行选项我们可以进行更多的控制。

这个命令的参数及作用如下:


EdmGen 选项

/mode:EntityClassGeneration 从 csdl 文件生成对象

/mode:FromSsdlGeneration 从 ssdl 文件生成 msl、csdl 和对象

/mode:ValidateArtifacts 验证 ssdl、msl 和 csdl 文件

/mode:ViewGeneration 从 ssdl、msl 和 csdl 文件生成映射视图

/mode:FullGeneration 从数据库生成 ssdl、msl、csdl 和对象

/project:<字符串> 用于所有项目文件的基名称 (短格式: /p)

/provider:<字符串> 用于 ssdl 生成的 Ado.Net 数据提供程序的名称。(短格式: /prov)

/connectionstring:<连接字符串> 您要连接到的数据库的连接字符串 (短格式: /c)

/incsdl:<文件> 从中读取概念模型的文件

/refcsdl:<文件> 包含 /incsdl 文件所依赖的类型的 csdl 文件

/inmsl:<文件> 从中读取映射的文件

/inssdl:<文件> 从中读取存储模型的文件

/outcsdl:<文件> 将生成的概念模型写入到其中的文件

/outmsl:<文件> 将生成的映射写入到其中的文件

/outssdl:<文件> 将生成的存储模型写入到其中的文件

/outobjectlayer:<文件> 将生成的对象层写入到其中的文件

/outviews:<文件> 将预生成的视图对象写入到其中的文件

/language:CSharp 使用 C# 语言生成代码

/language:VB 使用 VB 语言生成代码

/namespace:<字符串> 用于概念模型类型的命名空间名称

/entitycontainer:<字符串> 用于概念模型中的 EntityContainer 的名称

/help 显示用法信息 (短格式: /?)

/nologo 取消显示版权消息

使用示例:

从 Northwind 示例数据库生成完整 Entity Model。


EdmGen /mode:FullGeneration /project:Northwind /provider:System.Data.SqlClient /connectionstring:"server=.\sqlexpress;integrated security=true; database=northwind"

从 ssdl 文件开始生成 Entity Model。


EdmGen /mode:FromSSDLGeneration /inssdl:Northwind.ssdl /project:Northwind

验证 Entity Model。


EdmGen /mode:ValidateArtifacts /inssdl:Northwind.ssdl /inmsl:Northwind.msl /incsdl:Northwind.csdl

为什么要使用Entity Framework,限制条件及当前版本框架的问题

  • 优势

通过对比上面图4与图2、图3我们可以很清楚的看到使用Entity Framework一个很大的好处,我们可以把实体类的定义由一个单独的项目使用C# class完成这样一种设计方式转变为使用xml文件定义并集成到数据访问层。

在以往要在一个项目中动态创建实体,我所知的方法是把要添加的实体放入一个程序集,然后通过反射加载程序集。现在可以通过动态更改EDM的方法来增加实体并将其映射到数据库,后者是以前无法实现的。

便于更改数据库,当更换数据库后,只需修改SSDL的定义,(如果数据库的表明有变动,也只需多修改MSL),对CSDL没有任何影响,从而也不需要对程序的BLL等上层部分做任何改动。

  • 条件

要想让一个数据库支持Entity Framework,一个必要条件就是该数据库需提供相应的Entity Client Data Provider,这样才能将Entity SQL转换为针对此数据此数据库的SQL并交由ADO.NET来执行。当然该数据库还需要提供ADO.NET Data Provider。

  • 缺陷

Entity Framework技术的效率问题是其几乎唯一一个稍有不足之处。首先其将EntitySQL转换为SQL的方式属于解释性转换,性能较差。另外Entity Framework在每次应用启动时需要读取EDM,这个过程较慢(但在后续操作时,就不再存在这个问题)。

EDM中的DML

由于当前的EntitySQL不支持DML操作,所以当前版本的Entity Framework的插入、更新及删除操作需要通过Object Service来完成。在EDM的设计器文件xxx.designer.cs中自动生成了一些签名为

void AddToEntity(EntityTypeentity)

的方法。我们只需要新建一个实体对象并调用这个方法添加实体即可。注意这个函数内部调用

entities.AddObject("EntitySetName",entity);

最后调用entities.SaveChanges()方法将修改保存回数据库,这是所有三种更新操作所需的。更新与删除操作都需要先使用ObjectService定位操作的实体对象,更新操作直接使用赋值运算符,删除操作则调用

entites.DeleteObject(object o);

方法。之后调用entities.SaveChanges()方法保存,这个过程简单,不再赘述。

含有Association的EDM的使用

当前版本的Entity Framework不支持自动延迟加载,所有当前未使用的关系中的相关实体默认按不加载处理,当我们需要通过关系获取一个实体对象时,我们可以采用两种方法:

  1. 显示加载 实体框架针对 EntityReference 类的每个实例提供一个 Load 方法。此方法可用于显式加载与另一实体相关的一个集合。我们只需在访问关系中实体之前调用其Load即可,当然提前判断该实体是否已经加载是一种比较好的实践。如下代码所示

using (Entities entities = new Entities())

{

var query = (from o in entities.Orders

where o.Customers.CustomerID == "ALFKI"

select o);

foreach (Orders order in query)

{

if (!order.CustomersReference.IsLoaded)

order.CustomersReference.Load();

Console.WriteLine(order.OrderID + " --- " +

order.Customers.CompanyName);

}

}

  1. 预先加载

    先看代码示例

using (Entities entities = new Entities())

{

var query = (from o in entities.Orders.Include("Customers")

where o.ShipCountry == "USA"

select o);

foreach (Orders order in query)

Console.WriteLine(order.OrderID + " --- " +

order.Customers.CompanyName);

}

查询中针对 Orders 实体调用的 Include 方法接受了一个参数,该参数在本示例中将要求查询不仅要检索 Orders,而且还要检索相关的 Customers。这将生成单个 SQL 语句,它会加载满足 LINQ 查询条件的所有 Order 和 Customer。

两种加载关系实体的方式的选择根据:如果针对关系数据你只需做一到两次查询,则使用显示加载更高效,如果要持续访问关系实体中数据,则使用预先加载。

关系下的添加,更新与删除与上述操作基本相同,唯一需要注意的是删除操作不支持级联删除,需要手工遍历所有的相关项并将其一一删除。注意这里删除操作不能使用foreach来遍历需要删除的关系实体。取而代之的有两种方法:

  1. while法

while (result.Order_Details.Count > 0)

{

//删除操作…

}

  1. ToList法(以非联机方式操作)

    var items = result.Order_Details.ToList();

    foreach (var item in items)

    {

    //删除操作…

    }

最新补充

Entity Framework在开发中的应用 – Entity Framework与控件

.NET Framework提供了许多xxxDataSource控件,如SqlDataSource,ObjectDataSource等,这些数据源控件大大方便了我们的数据绑定操作。不幸的是目前还没有针对Entity Framework的数据源控件发布,但是将数据绑定到诸如ListBox,Grrdview或DetailsView控件也是很简单的。这源于使用ObjectContext操作返回的IQueryable<T>对象或是使用EntityClient查询返回的ObjectQuery对象都实现了IEnumerable接口。这样很容易将这些数据绑定到数据显示控件。更新操作可以按上文所述在相应的时间处理函数中写更新EDM的程序即可。

Entity Framework的链接字符串

默认情况下(Visual Studio对Entity Framework数据项目的默认设置),EDM这个XML文件被作为资源在编译时嵌入到程序集中。这种情况下当更改EDM后需要重新编译这个程序集才能使更改生效。通过更改项目属性也可以让EDM作为三个独立的XML文件存在于项目中。为了让应用程序可以找到EDM(无论其以什么方式存储)需要一个链接字符串来指示EDM所在的位置。实体模型设计器生成的链接字符串如下所示:


<addname="ASSEntities"

connectionString="

metadata=res://*/ass.csdl|

res://*/ass.ssdl|

res://*/ass.msl;

provider=System.Data.SqlClient;

provider connection string=&quot;Data Source=(local);Initial Catalog=ASS;Integrated Security=True;MultipleActiveResultSets=True&quot;"

providerName="System.Data.EntityClient" />

http://msdn.microsoft.com/zh-cn/library/cc716756.aspx

关键的一点应用程序是怎样找到这个字符串的,对于使用EntityClient的情况,可以直接将连接字符串赋给EntityConnection的ConnectionString属性,另外对于使用ObjectContext,其可以自动由配置文件检索这个连接字符串。

时间: 2024-09-30 19:05:21

Entity Framework的原理及使用方式的相关文章

[原创]Entity Framework查询原理

前言 Entity Framework的全称是ADO.NET Entity Framework,是微软开发的基于ADO.NET的ORM(Object/Relational Mapping)框架.Entity Framework的主要特点:1. 支持多种数据库(Microsoft SQL Server, Oracle, and DB2):2. 强劲的映射引擎,能很好地支持存储过程:3. 提供Visual Studio集成工具,进行可视化操作:4. 能够与ASP.NET, WPF, WCF, WCF

2. Code First Migrations With Entity Framework【EF中 Code-First 方式的数据库迁移】

前面的文章中,学习了EF 中的几种关系,一对一,一对多,多对多.但是相信大家肯定会有疑问: 1.我难道每次都要创建数据库么? 2.我怎么样从已经存在的表中,添加字段和移除字段呢? 3.当我向表中,添加字段或者移除字段,我怎么来避免丢失数据呢? 4.当数据库发生改变的时候,我怎么获取到创建数据库的脚本呢? 不用着急,这篇文章,我会向大家一一讲到: 首先,说说我们为什么要使用数据库迁移技术吧,因为我们的实体总是变动地很频繁,在上篇文章中,我们使用了数据库初始化策略来做,也就是每次当数据库不存在的时候

Entity Framework 全面教程详解(转)

目录 预备知识    2 LINQ技术 2 LINQ技术的基础 - C#3.0    2 自动属性    2 隐式类型    2 对象初始化器与集合初始化器    3 匿名类    3 扩展方法    4 Lambda表达式    4 .NET中的数据访问    4 DataSet方案    5 改进的的DataSet方案    5 手写代码通过ADO.NET2.0连接类与数据库交互    5 ORM – LINQ to SQL    6 深入了解Entity Framework    7 En

深入了解Entity Framework框架及访问数据的几种方式

一.前言 1.Entity Framework概要 Entity Framework是微软以ADO.NET为基础所发展出来的对象关系映射(O/R Mapping)解决方案.该框架曾经为.NET Framework的一部分,但Version 6之后从.NET Framework分离出来,可通过NuGet获取. Entity Framework利用抽象化数据结构的方式,将每个数据库对象都转换成应用程序对象 (Entity),而数据字段都转换为属性 (Property),关系则转换为结合属性 (Ass

《Entity Framework 6 源码分析》

背景 以Code First方式编写简单代码,按源码执行过程,逐步讲解Entity Framework工作原理.本系列博文系我学习Entity Framework 6 Code First的总结之作.学习过程中参考了大量MSDN资料,因参考资料过多,且皆可从EF主页索引到,故不一一列举.所有阅读过的正式出版的书籍,详见参考文献一节.部分章节因论述需要所引用其它.NET书籍将在该章节内注明引用信息.为了分析代码,我经常访问.NET参考源码页面. 因水平有限,若有谬误,恳请指正,同时欢迎企鹅群185

第一篇:Entity Framework 简介

先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发ORM框架首先要了解ORM概念. ORM 对象关系映射,O(Object) 对象,在项目中就是实体,更加精确的来说就是数据Model,也可以说持久化类.R(Relation) 关系数据,M (Mapping)映射,将对象映射到关系数据,将关系数据映射到对象的过程. 更加直观理解就是,ORM 就是以OO

Entity Framework 学习笔记(一)之数据模型 数据库

关于Entity Framework  数据模型 的开发有三种模式:1.引用数据库方式:2.在VS中新建EF空模型Model 方式:3.Code 方式 Entity Framework  数据模型  引用"引用数据库方式"进行开发创建的使用,具体如下: 开发环境:VS2012 数据库:SQL Server 2008 Entity Framework  版本:6.12 1.新建数据库 在数据库中新建数据库,并创建数据表,以下截图只供参考: 2.新建项目 在VS中新建一个控制台应用程序 F

Entity Framework Code First数据库连接

参考页面: http://www.yuanjiaocheng.net/entity/entitytypes.html http://www.yuanjiaocheng.net/entity/entity-relations.html http://www.yuanjiaocheng.net/entity/entity-lifecycle.html http://www.yuanjiaocheng.net/entity/code-first.html http://www.yuanjiaochen

MVC5+EF6--1 创建Entity Framework数据模型

近期学习MVC5+EF6,找到了Microsoft的原文,一个非常棒的系列,Getting Started with Entity Framework 6 Code First using MVC 5,网址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-appli