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,其可以自动由配置文件检索这个连接字符串。

最新文章

  1. CentOS中Mysql常用操作
  2. Yii2 用户登录
  3. UIkit框架之uiUIapplication
  4. 说说 PWA 和微信小程序--Progressive Web App
  5. HtmlAgilityPack 之 HtmlNode类
  6. Javascript 异步加载详解
  7. Git CMD - config: Get and set repository or global options
  8. JDK + Tomcat 安装配置
  9. 【转】Logistic regression (逻辑回归) 概述
  10. 适配器模式—STL中的适配器模式分析
  11. 如何插上U盘 自动复制内容
  12. Git 的是使用入门
  13. Spring基础学习(一)&mdash;初识Spring
  14. PHP基础知识1
  15. 使用python爬取百度贴吧内的图片
  16. linux c 开发通用结构,框架
  17. c/c++ 标准库 插入迭代器 详解
  18. Html.Partial,Html.RenderPartial Html.Action,Html.RenderAction区别
  19. 迪杰斯特拉算法dijkstra(可打印最短路径)
  20. Java编写email实现内容换行

热门文章

  1. 以下三种下载方式有什么不同?如何用python模拟下载器下载?
  2. 查询SqlServer最近执行过的Sql
  3. ui5 call view or method from another view
  4. 联想服务器thinkserver TS550 Raid5制作及winserver2012R2 安装过来
  5. SSD-tensorflow-2 制作自己的数据集
  6. FastDFS学习总结(1)--FastDFS安装和部署
  7. 基于Verilog语言的可维护性设计技术
  8. BootstrapDialog模态框
  9. POJ 1330 Nearest Common Ancestors 倍增算法的LCA
  10. RedHat Linux 下安装、测试摄像头