SlideShare a Scribd company logo
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 

 Entity  Framework 的核心  –  EDM(Entity  Data  Model)  7 

     EDM 概述  7 

     EDM 之 CSDL  7 

     EDM 之 SSDL  11 

     EDM 之 MSL  12 

     EDM 中存储过程的设计  15 

     EDM 中 ComplexType 的设计  16 

     实体数据模型映射方案  17 

 Entity  Framework 的原理及使用方式  18 

     各种使用方式总结  18 

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

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

     其它操作 EDM 的方式  22 

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

     含有 Association 的 EDM 的使用  23 




本文档主要介绍.NET 开发中两项新技术,.NET 平台语言中的语言集成查询技术  ­  LINQ,与 ADO.NET 
中新增的数据访问层设计技术 ADO.NET  Entity  Framework。ADO.NET 的 LINQ  to  Entity 部分以 LINQ 
为基础,为了完整性本文档首先介绍 LINQ 技术。 


预备知识 


LINQ 技术 
LINQ 是.NET  3.5 中新增的一种技术,这个技术扩展了.NET 平台上的编程语言,使其可以更加方便的进行 

数据查询,单纯的 LINQ 技术主要完成对集合对象(如 System.Collection 下或 System.Collection.Generi 
c 命名空间下的对象)的查询。结合 LINQ  Provider 可以实现对 XML 文件(使用 LINQ  to  XML  –  位于 S 
ystem.Xml.Linq 命名空间下的类),数据库(可以使用 LINQ  to  SQL 或下文要详细介绍的 LINQ  to  Entit 
y)等对象的操作。 



LINQ 是一种运行时无关的技术,其运行于 CLR2.0 之上,微软对 C#3.0 与 VB9.0 的编译器进性扩展,从 
而使其可以将 LINQ 编写的程序编译为可以被 CLR2.0 的 JIT 所理解的 MSIL。 




LINQ 技术的基础  ­  C#3.0

 ·    自动属性


 ·    隐式类型


 ·    对象集合初始化器


 ·    匿名类


 ·    扩展方法


 ·    Lambda 表达式 



自动属性
这个概念很简单,其简化了我们在.NET 的时候手写一堆私有成员+属性的编程方式,我们只需要使用如下 
方式声明一个属性,编译器会自动生成所需的成员变量。 

public  class  Customer 

{ 

public  int  Id  {  get;  set;  } 

public  string  Name  {  get;  set;  } 

} 

     在我使用 LINQ 完成的项目中,使我了解到自动属性方便的一个用途如下: 

     在使用 LINQ 获取数据的过程中,我们常常需要使用 select  new 语句查询出一个对象(往往是 IEnumer 
able 类型的)用于数据绑定。在一般情况下如果是直接绑定(如直接将查询结果赋给一个 Gridview 控件的 
DataSource 属性)我们可以直接 select  new 来返回一个匿名类的对象。如果我们还需要对这个集合对象 
进行进一步操作,我们将必须使用 select  new  class­name 这样的语言返回一个类的对象,大部分情况下 
这个类只作为实体的一个结构而不需要完成一些操作操作,这时候使用自动属性来完成这个类将是非常简 
洁高效的。 


隐式类型 

这个名称可能对你很陌生,但是 var 这个关键字应该都用过,在 C#中使用 var 声明一个对象时,编译器会 

自动根据其赋值语句推断这个局部变量的类型。赋值以后,这个变量的类型也就确定而不可以再进行更改。 
另外 var 关键字也用于匿名类的声明。 

     应用场合:var 主要用途是表示一个 LINQ 查询的结果。这个结果可能是 ObjectQuery<>或 IQueryable< 
>类型的对象,也可能是一个简单的实体类型的对象。这时使用 var 声明这个对象可以节省很多代码书写上 
的时间。 


对象初始化器与集合初始化器 

     在.NET2.0 中构造一个对象的方法一是提供一个重载的构造函数, 
                                      二是用默认的构造函数生成一个对象, 
然后对其属性进行赋值。在.NET3.5/C#3.0 中我们有一种更好的方式来进行对象的初始化。那就是使用对 
象初始化器。这个特性也是匿名类的一个基础,所以放在匿名类之前介绍。 

     还是那就话,好的代码强于注释,下面用几个代码段说明初始化器: 

(代码出自:李永京的博客  http://lyj.cnblogs.com) 

基本用法: 

User  user  =  new  User  {  Id  =  1,  Name  =  "YJingLee",  Age  =  22  }; 

嵌套使用: 

User  user  =  new  User 

{
Id  =  1, 

      Name  =  "YJingLee", 

      Age  =  22, 

      Address  =  new  Address 

      { 

           City  =  "NanJing", 

           Zip  =  21000 

      } 

}; 

      类似于对象初始化器初始化一个对象,集合初始化器初始化一个集合,一句话,有了它你就不用在将元 
素通过 Add 逐个添加了。仍然给出代码示例: 

基本使用: 

List<int>  num  =  new  List<int>  {  0,  1,  2,  6,  7,  8,  9  }; 

结合对象初始化器,我们可以写出如下简洁的代码: 

List<User>  user  =  new  List<User>{ 

new  User{Id=1,Name="YJingLee",Age=22}, 

new  User{Id=2,Name="XieQing",Age=25}, 

}; 

应用场合: 

      还是前文提到的 select  new  class­name 语法,后面可以直接接一个初始化器来将查询结果返回到这个 
对象。 


匿名类 

有了前文初始化器的介绍, 
            匿名类就很简单了。 
                    我们可以使用 new  {  object  initializer  }或 new[]{  object,  …} 
来初始化一个匿名类或不确定类型的数组。匿名类的对象需要使用 var 关键字声明。示例代码: 

var  p1  =  new  {  Id  =  1,  Name  =  "YJingLee",  Age  =  22  }; 

应用场合: 

还是同上面的例子提到的当直接使用 select  new  {  object  initializer  }这样的语法就是将一个 LINQ 查询的 
结果返回到一个匿名类中。 


扩展方法
扩展方法是 C#中新增的很重要的特性之一。其对于 LINQ 的实现起着关键的作用。在.NET2.0 时代是没 
有 LINQ 的,所以.NET2.0 以及之前版本中的集合类在设计的时候没有预留用于 LINQ 的方法。为了在不破 
坏这个类现有封装的前提下又可以为其添加 LINQ 的支持就需要用到扩展方法。 

     扩展方法使用上类似于静态方法,但在本质上其是实例方法。这是由于.NET3.5 的运行环境仍然为 CLR 
2.0 所以语言不可能做很大的变革,这一切都是语法糖。 

下面仍然通过一段代码来说明扩展方法的实现: 

(代码出自:李永京  http://lyj.cnblogs.com) 

public  static  class  Extensions 

{ 

public  static  bool  IsValidEmailAddress(this  string  s) 

     { 

Regex  regex  =  new  Regex(@"^[w­.]+@([w­]+.)+[w­]{2,4}$"); 

return  regex.IsMatch(s); 

     } 

} 

如上代码所示,扩展方法为一静态方法,声明于一个静态类,其参数前加上一个 this 关键字,参数的类型 
表示这个扩展方法要对这个类型进行扩展。如上述代码表示其要对字符串类型进行扩展。 

在应用上扩展方法被作为其扩展的类型的静态方法来调用。如下: 

if  (email.IsValidEmailAddress()) 

{ 

     Response.Write("YJingLee 提示:这是一个正确的邮件地址"); 

} 


Lambda 表达式 

Lambda 表达式是对.NET2.0 中匿名方法在语法形式上的进一步改进,仍然以代码说明: 

var  inString  =  list.FindAll(delegate(string  s)  {  return  s.Indexof("YJingLee")  >=  0;  }); 

使用 Lambda 表达式代码将更自然易懂。 

var  inString  =  list.FindAll(s  =>  s.Indexof("YJingLee")  >=  0); 

可以看出,Lambda 表达式格式为:(参数列表)=>表达式或语句块 

“Lambda  表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类 
型。
所有  Lambda  表达式都使用  Lambda  运算符  =>,该运算符读为“goes  to”。该  Lambda  运算符 
的左边是输入参数(如果有),右边包含表达式或语句块。Lambda  表达式  x  =>  x  *  x  读作“x  goes  t 
o  x  times  x”。可以将此表达式分配给委托类型,如下所示: 

   delegate  int  del(int  i); 

   del  myDelegate  =  x  =>  x  *  x; 

   int  j  =  myDelegate(5);  //j  =  25 

   创建表达式目录树类型: 

   using  System.Linq.Expressions; 

   //  ... 

   Expression<del>  =  x  =>  x  *  x; 

   =>  运算符具有与赋值运算符  (=)  相同的优先级,并且是右结合运算符。 

   Lambda  用在基于方法的  LINQ  查询中,作为诸如  Where  和  Where  等标准查询运算符方法的参 
数。 

   使用基于方法的语法在  Enumerable  类中调用  Where  方法时 
                                           (像在  LINQ  to  Objects  和  LINQ  to 
XML  中那样),参数是委托类型  System..::.Func<(Of  <(T,  TResult>)>)。使用  Lambda  表达式创建委 
托最为方便。例如,当您在  System.Linq..::.Queryable  类中调用相同的方法时(像在  LINQ  to  SQL  中 
那样),则参数类型是  System.Linq.Expressions..::.Expression<Func>,其中  Func  是包含至多五个输 
入参数的任何  Func  委托。同样,Lambda  表达式只是一种用于构造表达式目录树的非常简练的方式。尽 
管事实上通过  Lambda  创建的对象的类型是不同的,但  Lambda  使得  Where  调用看起来类似。 

   在前面的示例中,请注意委托签名具有一个  int  类型的隐式类型输入参数,并返回  int。可以将  Lam 
bda  表达式转换为该类型的委托,因为该表达式也具有一个输入参数  (x),以及一个编译器可隐式转换为 
int  类型的返回值。(以下几节中将对类型推理进行详细讨论。)使用输入参数  5  调用委托时,它将返回 
结果  25。 

   在  is  或  as  运算符的左侧不允许使用  Lambda。 

   适用于匿名方法的所有限制也适用于  Lambda  表达式。有关更多信息,请参见匿名方法(C#  编程指 
南)。

   下列规则适用于  Lambda  表达式中的变量范围: 

   捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。 

   在外部方法中看不到  Lambda  表达式内引入的变量。 

   Lambda  表达式无法从封闭方法中直接捕获  ref  或  out  参数。 

   Lambda  表达式中的返回语句不会导致封闭方法返回。 

   Lambda  表达式不能包含其目标位于所包含匿名函数主体外部或内部的  goto  语句、break  语句或  c 
ontinue  语句。 


.NET 中的数据访问
这一部分介绍.NET 中不同的数据访问层的使用方式, 
                              由此得出 Entity  Framework 在一个.NET 系统中的应 
    用及其在原有设计基础上的改变。从大的方面来看数据访问的设计方案基本有如下几类:


·        DataSet


·        手写代码通过 ADO.NET2.0 连接类与数据库交互


·        ORM 组件 



    DataSet 方案 
    最基本的 Dataset 数据访问的实现使用下图表示: 




                                 图 1 

    如图所示,DataSet 与数据源之间通过 DataAdapter 连接,逻辑中直接访问 DataSet 获取数据,或是通过 
    ADO.NET2.0 的非连接类,或者通过强类型 DataSet 以一种类型安全的方式访问数据。 

     缺点逻辑代码与数据访问代码耦合高。 



    改进的的 DataSet 方案 




                                 图2
这种设计方式将业务所需的实体抽象出来,并把对 DataSet 的操作封装在其中,这样一定程序上解除业务 
逻辑与数据访问间的耦合。 



手写代码通过 ADO.NET2.0 连接类与数据库交互 
这种方式是我使用的最多的一种方式,其可以提供最大的控制能力,且效率最高,唯一的不足是当业务变 
化时修改数据访问代码的工作量比较大,通过代码生成器也能一定程度上解决这个问题 




ORM  –  LINQ  to  SQL 
在.NET 平台下 ORM 的解决方案有不少,本文只讨论两个微软官方的解决方案。先是 LINQ  to  SQL 技术。 

LINQ  to  SQL 是一个将不再更新的技术。其有很多不足之处,如,不能灵活的定义对象模型与数据表之间 
的映射、无法扩展提供程序只能支持 SQL  Server 等。 

这样数据访问层的设计如下所示: 




                            图 3 




ORM  –  ADO.NET  Entity  Framework 
作为下一代数据访问的技术领导者。Entity  Framework 的设计很多地方都保留了高扩展性。其最重要的一 
个改进在于其映射定义的灵活性。先来看下图:
图 4 

    由图可以看出,使用 Entity  Framework 可以充分的定义与数据库表映射的实体,并将这个实体直接用于业 
    务逻辑层或作为服务的数据契约。实体设计较其他技术的优势体现在以下几方面:


·         创建 ComplexType(CSDL 部分有讨论)


·         EntitySet 的继承 


    使用 Entity  Framework 后,可以将实体类的设计工作完全放在 EDM 的设计过程中,而不再需要手工写一 
    些大同小异的代码,并且对这个实体模型(包含于 EDM 中)可以在运行时修改并生效。另外,开发人员 
    与数据库直接打交道的次数将大大减少,大部分时间开发人员只需操作实体模型,框架会自动完成对数据 
    库的操作。下文将详细讨论上图所示的 EDM。 


    深入了解 Entity  Framework 


    Entity  Framework 的核心  –  EDM(Entity  Data  Model) 

    EDM 概述 

    实体数据模型,简称 EDM,由三个概念组成。概念模型由概念架构定义语言文件  (.csdl)来定义,映射由 

    映射规范语言文件  (.msl),存储模型(又称逻辑模型)由存储架构定义语言文件  (.ssdl)来定义。这三者合 
    在一起就是 EDM 模式。EDM 模式在项目中的表现形式就是扩展名为.edmx 的文件。这个包含 EDM 的文 
    件可以使用 Visual  Studio 中的 EDM 设计器来设计。由于这个文件本质是一个 xml 文件,可以手工编辑此 
    文件来自定义 CSDL、MSL 与 SSDL 这三部分。下面详细分析一下这个 xml 文件及三个其重要组成部分: 



    这个文件展示了示例项目完整的 EDM 文件的 XML 形式: 

    文件 

    这个设计器生成的文件的注释可以使你很清楚的明白这个 EDM 文件的组成。一点点分析一下,第一行表 
    明这是一个 xml 文件。
<?xml version="1.0" encoding="utf­8"?> 

以下这一行是 EDM 的根节点,定义了一个表明版本的属性及这个 EDM 使用的命名空间: 

<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"> 

接下来由注释可以看到 EDM 被分为两部分,第一部分是 EDM 的核心,第二部分用于实体设计器,这一部 
分不用研究。 

第一部分中节点<edmx:Runtime>下定义了以下三部分: 


EDM 之 CSDL 

  CSDL 定义了 EDM 或者说是整个程序的灵魂部分  –  概念模型。 
                                      当前流行的软件设计方法通常都是由设 
计其概念模型起步。说概念模型可能比较抽象一个更容易接受的名字就是实体类。实体类是面向对象设计 
中一个最根本的组成部分,其体现了现实世界中对象作为一种计算中可以表示的对象设计方法。而 EDM 
的 CSDL 就是要达到这样一个目的。这个在下文介绍 Entity  Framework 优点时另有说明。 

  这个文件完全以程序语言的角度来定义模型的概念。即其中定义的实体、主键、属性、关联等都是对应 
于.NET  Framework 中的类型。下面 xml  element 来自作业提交系统(有删节): 

<!­­ CSDL content ­­> 

<edmx:ConceptualModels> 

<Schema Namespace="ASSModel" Alias="Self" 
xmlns="http://schemas.microsoft.com/ado/2006/04/edm"> 

<EntityContainer Name="ASSEntities"> 

<FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments" 
ReturnType="Collection(Self.UpAssignments)"> 

<Parameter Name="StuID" Type="Int32" Mode="In" /> 

<Parameter Name="ClassID" Type="Int32" Mode="In" /> 

<Parameter Name="Semester" Type="String" Mode="In" /> 

</FunctionImport> 

<!­­  以上删节  – 5 个存储过程  ­­> 



<EntitySet Name="Assignments" EntityType="ASSModel.Assignments" /> 

<EntitySet Name="Classes" EntityType="ASSModel.Classes" /> 

<EntitySet Name="Courses" EntityType="ASSModel.Courses" /> 

<EntitySet Name="SetCourses" EntityType="ASSModel.SetCourses" /> 

<EntitySet Name="Students" EntityType="ASSModel.Students" /> 

<EntitySet Name="Teachers" EntityType="ASSModel.Teachers" /> 

<EntitySet Name="UpAssignments" EntityType="ASSModel.UpAssignments" />
<AssociationSet Name="FK_SetCourses_Classes" Association="ASSModel.FK_SetCourses_Classes"> 

<End Role="Classes" EntitySet="Classes" /> 

<End Role="SetCourses" EntitySet="SetCourses" /> 

</AssociationSet> 

<!­­  以上删节  – 6 个关系集  ­­> 



</EntityContainer> 



<!­­  以下保留一个 EntityType 作为示例  ­­> 

<EntityType Name="Students"> 

<Key> 

<PropertyRef Name="StuID" /> 

</Key> 

<Property Name="StuID" Type="Int32" Nullable="false" /> 

<Property Name="StuName" Type="String" Nullable="false" MaxLength="10" Unicode="true" 
FixedLength="true" /> 

<Property Name="Pswd" Type="String" Nullable="false" MaxLength="50" Unicode="false" 
FixedLength="true" /> 

<NavigationProperty Name="Classes" Relationship="ASSModel.FK_Students_Classes" 
FromRole="Students" ToRole="Classes" /> 

<NavigationProperty Name="UpAssignments" Relationship="ASSModel.FK_UpAssignments_Students" 
FromRole="Students" ToRole="UpAssignments" /> 

</EntityType> 



<!­­  仅保留与上文 AssociationSet 对应的 Association ­­> 

<Association Name="FK_SetCourses_Classes"> 

<End Role="Classes" Type="ASSModel.Classes" Multiplicity="1" /> 

<End Role="SetCourses" Type="ASSModel.SetCourses" Multiplicity="*" /> 

</Association> 

</Schema> 

</edmx:ConceptualModels> 

这部分 XML 文档,Schema 是 CSDL 的根元素,其中定义的 Namespace 是用于 ObjectContext 与 Entity 

Class 的命名空间,Alias­别名为此命名空间 Namespace 指定一个易记的名称,在定义 Alias 之后,在此 S 
chema 内的 Element 均可以该 Alias 作为 Namespace 的别名。Alias 的使用可以参考如下 xml  element: 

<FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments"
ReturnType="Collection(Self.UpAssignments)"> 

在这个根元素的内部的文档结构第一部分  –  实体容器大致如下: 

<EntityContainer /> 

<FunctionImport /> 

<EntitySet /> 

<AssociationSet /> 

</EntityContainer> 

下面的表格说明了这些节点及其属性的作用 

EntityContainer 

Name                   EntityContainer 的名称,其将作为产生的 ObjectContext 类的名称 

    EntitySet 

    Name               ObjectContext 内与此 Entity 类型对应的属性名 

    EntityType         ObjectContext 内与此 Entity 类型对应的属性的类型 

    AssociationSet 

          End          有两个 End 子节点,分别描述建立此关系的两个 EntitySet 

                       对应到 Association 中 End 节的 Role 属性,起到将 AssociationSet 与 Association 
          Role 
                       相关连的作用。 

    FunctionImport  详见存储过程设计部分 

可以看出,Entity 与 Assciation 都被分开定义与两个部分,这样设计是出于当有多个 EntityContainer 时, 
其中的 EntitySet 或 AssociationSet 可以共享 Entity 或 Association 的定义。 

  接下来看一下 CSDL 中最后一部分,Entity 与 Association 的定义。 

首先是 Entity: 

<EntityType  Name="Students"> 

<Key> 

<PropertyRef  Name="StuID"  /> 

</Key> 

<Property  Name="StuID"  Type="Int32"  Nullable="false"  /> 

<Property  Name="StuName"  Type="String"  Nullable="false"  MaxLength="10"  Unicode="true"  FixedL 
ength="true"  /> 

<Property  Name="Pswd"  Type="String"  Nullable="false"  MaxLength="50"  Unicode="false"  FixedLeng 
th="true"  />
<NavigationProperty  Name="Classes"  Relationship="ASSModel.FK_Students_Classes"  FromRole="St 
udents"  ToRole="Classes"  /> 

<NavigationProperty  Name="UpAssignments"  Relationship="ASSModel.FK_UpAssignments_Students 
"  FromRole="Students"  ToRole="UpAssignments"  /> 

</EntityType> 



下表说明了其属性及其子节点与子节点的属性的含义: 

EntityType 

Name                    Entity Class 的名称 

Abstract                是否为抽象类 

BaseType                父类 

   Key                  主键 

          Property      主键之属性 

          Name          属性名 

   Property             属性 

   Name                 属性名 

   Type                 属性类型 

   Nullable             是否允许 null 

   MaxLength            属性最大长度 

   FixLength            是否固定长度 

   NavigationProperty  关系属性 

   Name                 属性名 

   Relationship         对应的 Association 

   FromRole、ToRole  区别关系两方的父与子 

最后 Association 节,这是真正定义关系的地方。首先看示例: 

<!­­  仅保留与上文 AssociationSet 对应的 Association  ­­> 

<Association  Name="FK_SetCourses_Classes"> 

<End  Role="Classes"  Type="ASSModel.Classes"  Multiplicity="1"  /> 

<End  Role="SetCourses"  Type="ASSModel.SetCourses"  Multiplicity="*"  /> 

</Association>
这一节符合以下结构: 

<Association> 

<End /> 

<ReferentialConstraint> 

<Principal> 

<PropertyRef /> 

</Principal> 

<Dependent> 

<PropertyRef /> 

</Dependent> 

</ReferentialConstraint> 

</Association> 




属性及其子元素属性的说明: 

Association 

Name                        Association 的名称 

   End                      类似于 AssociationSet,Association 也有两个 End 节点。 

   Name                     End 名称 

   Type                     EntityType 的名称 

   Role                     此 End 的 Role,与 AssociationSet 的 End 的 Role 属性相联系 

   Multiplicity             关联多重性,值为 0、1 或* 

   ReferentialConstraint  外键条件限制 

        Principal           主要条件 

        Role                对应于 End 中的 Role 

           PropertyRef      外键属性 

           Name             属性名称 

        Dependent           依存条件 

        Role                对应于 End 中的 Role 

           PropertyRef      外键属性 

           Name             属性名
另外上面示例未涉及的概念,如下: 

视图 

  在 EDM 设计器中添加视图基本与添加实体表一致,所生成的 xml 自行对照。某些环境下可能无法添加 
视图,原因未知,另外对于没有主键的表目前版本 EntityFramework 支持不好,在设计器中无法添加,及 
时通过手工编辑 xml 的方式强行添加,在使用过程中也会出现问题。 

ComplexType(复杂类型) 

按 MSDN 中的例子,先描述如下场景。在一个销售系统中我们需要在一个订单中包含一个描述客户地址的 
实体,而这个实体又能良好的与存储模型映射起来,由于数据库不支持地址这种类型,所以我们可以将地 
址的每个字段与数据库相映射。且在概念模型中,及在 C#代码可以控制的范围内,地址仍然作为一个独立 
的类型存在。由于 EDM 设计器不支持以可视化方式创建 Complex  Type,我们需要手动编辑 CSDL 与 MS 
L 来完成复杂类型的创建与映射。这部分示例将在介绍 MSL 后给出。 




EDM 之 SSDL 

这个文件中描述了表、列、关系、主键及索引等数据库中存在的概念。 

<!­­ SSDL content ­­> 

<edmx:StorageModels> 

<Schema Namespace="ASSModel.Store" Alias="Self" Provider="System.Data.SqlClient" 
ProviderManifestToken="2008" 
xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" 
xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl"> 

<EntityContainer Name="ASSModelStoreContainer"> 

<EntitySet Name="Assignments" EntityType="ASSModel.Store.Assignments" store:Type="Tables" 
Schema="dbo" /> 

<!­­  省略 7 个 EntitySet 的定义  ­­> 

</EntityContainer> 



<!­­  以下省略 7 个 EntityType 的定义  ­­> 

<EntityType Name="Assignments"> 

<Key> 

<PropertyRef Name="AssID" /> 

</Key> 

<Property Name="AssID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> 

<Property Name="AssName" Type="nchar" Nullable="false" MaxLength="20" />
<Property Name="AssDes" Type="nvarchar" MaxLength="500" /> 

<Property Name="SCID" Type="int" Nullable="false" /> 

<Property Name="Deadline" Type="datetime" Nullable="false" /> 

<Property Name="QuesFileName" Type="nvarchar" MaxLength="500" /> 

<Property Name="QuesFileUrl" Type="nvarchar" Nullable="false" MaxLength="500" /> 

</EntityType> 



<!­­  保留与 CSDL 中对应的 Function ­­> 

<Function Name="GETHOUSEWORKDONE" Aggregate="false" BuiltIn="false" NiladicFunction="false" 
IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo"> 

<Parameter Name="StuID" Type="int" Mode="In" /> 

<Parameter Name="ClassID" Type="int" Mode="In" /> 

<Parameter Name="Semester" Type="varchar" Mode="In" /> 

</Function> 



</Schema> 

</edmx:StorageModels> 

看文档的结构,SSDL 与 CSDL 很详细,只是其中 EntityType 等使用数据库的概念的描述。 

这其中有一个需要稍微介绍节点,DefiningQuery,首先看一下其出现的位置: 

EntityContainer 

     EntitySet 

           DefiningQuery  通过查询定义一个 SSDL 的 EntitySet 

                                  特定于存储的查询语句 

DefiningQuery 定义通过实体数据模型  (EDM)  内的客户端投影映射到数据存储视图的查询。 
                                                     此类映射是只 

读的。也就是说如果想要更新此类 EntitySet,需要使用下文介绍存储过程时提到的定义更新实体的存储过 
程的方法,使用定义的存储过程来更新这样的 EntitySet。当在实体类设计器中导入无主键的表时,会自动 
生成此类使用 DefiningQuery 定义的 EntitySet,要式样 Entity  Framework 提供的自动更新服务而不定义 
存储过程,需要给数据表添加一个适当的主键,删除 DefiningQuery 节点并更新数据模型。 


EDM 之 MSL 

这个文件即上面所述的 CSDL 与 SSDL 的对应,主要包括 CSDL 中属性与 SSDL 中列的对应。 

<!­­ C­S mapping content ­­> 

<edmx:Mappings>
<Mapping Space="C­S" xmlns="urn:schemas­microsoft­com:windows:storage:mapping:CS"> 

<EntityContainerMapping StorageEntityContainer="ASSModelStoreContainer" 
CdmEntityContainer="ASSEntities"> 

<EntitySetMapping Name="Assignments"> 

<EntityTypeMapping TypeName="IsTypeOf(ASSModel.Assignments)"> 

<MappingFragment StoreEntitySet="Assignments"> 

<ScalarProperty Name="QuesFileName" ColumnName="QuesFileName" /> 

<ScalarProperty Name="AssDes" ColumnName="AssDes" /> 

<ScalarProperty Name="AssID" ColumnName="AssID" /> 

<ScalarProperty Name="AssName" ColumnName="AssName" /> 

<ScalarProperty Name="Deadline" ColumnName="Deadline" /> 

<ScalarProperty Name="QuesFileUrl" ColumnName="QuesFileUrl" /> 

</MappingFragment> 

</EntityTypeMapping> 

</EntitySetMapping> 

<!­­  省略 EntitySetMapping 若干  ­­> 



<!­­  保留对应于 CSDL 与 SSDL 的 FunctionImportMapping ­­> 

<FunctionImportMapping FunctionImportName="GETHOUSEWORKDONE" 
FunctionName="ASSModel.Store.GETHOUSEWORKDONE" /> 



<AssociationSetMapping Name="FK_UpAssignments_Assignments" 
TypeName="ASSModel.FK_UpAssignments_Assignments" StoreEntitySet="UpAssignments"> 

<EndProperty Name="Assignments"> 

<ScalarProperty Name="AssID" ColumnName="AssID" /> 

</EndProperty> 

<EndProperty Name="UpAssignments"> 

<ScalarProperty Name="UpAssID" ColumnName="UpAssID" /> 

</EndProperty> 

</AssociationSetMapping> 

<!­­  省略 AssociationSetMapping 若干  ­­> 



</EntityContainerMapping> 

</Mapping> 

</edmx:Mappings>
如上代码所示, 
         MSL 的根节点为 Mapping, 
                           其中可以包含多个 EntityContainerMapping 
                                                         (上例只有一个), 

每一个 EntityContainerMapping 对应着两个分别来自 CSDL 与 SSDL 的 EntityContainer。 
                                                                   这个 EntityCont 
ainerMapping 就是描述这两个 EntityContainer 间的对应。下面再给出一段代码展示 EntityContainerMapp 
ing 的基本格式。 

<EntityContainerMapping StorageEntityContainer="" CdmEntityContainer=""> 

<EntitySetMapping> 

<EntityTypeMapping> 

<MappingFragment> 

<ScalarProperty /> 

</MappingFragment> 

<ModificationFunctionMapping> 

<InsertFunction /> 

<DeleteFunction /> 

<UpdateFunction /> 

</ ModificationFunctionMapping> 

</EntityTypeMapping> 

</EntitySetMapping> 



<AssociationSetMapping> 

<EndProperty> 

<ScalarProperty /> 

</EndProperty> 

</AssociationSetMapping> 



<FunctionImportMapping /> 

</EntityContainerMapping> 

同上文,下面列出这些节点的属性 

EntityContainerMapping 

StorageEntityContainer              SSDL 中的 EntityContainer 名称 

CdmEntityContainer                  CSDL 中的 EntityContainer 名称 

   EntitySetMapping                 EntityContainer 中每个 EntitySet 的对应 

   Name                             EntitySetMapping 的名称 

      EntityTypeMapping             描述 CSDL 中 EntityType 与 SSDL 中 EntityType 的对应
Name                              EntityTypeMapping 的名称 

                                     对应 CSDL 内 Entity 的名称  –  格式:IsTypeOf(<名称>) 
   TypeName 
                                     注:这个类及其子类将共享此 EntityTypeMapping 

      MappingFragment                描述属性及字段间的对应 

                                     SSDL 中的 EntitySet 名称 
      StoreEntitySet 
                                     (由于 CSDL 中一个 EntitySet 可以对应多个 SSDL 中的 EntitySet) 

           ScalarProperty            属性与字段对应 

           Name                      CSDL 中的属性名 

           ColumnName                SSDL 中的字段名称 

           Condition                 详见说明 2 

           ColumnName                列名 

           Value                     值 

      ModificationFunctionMapping    CUD 对应的存储过程 

           InsertFunction/ UpdateFunction / DeleteFunction 

           FunctionName 

   QueryView 

                                               Entity SQL 

                                     描述 CSDL 中的 AssociationSet 与 SSDL 中的 EntitySet 的对应关 
AssociationSetMapping 
                                     系 

Name                                 AssociationSetMapping 的名称 

StoreEntitySet                       SSDL 中 EntitySet 的名称 

TypeName                             CSDL 中 AssociationSet 的名称 

                                     一个 AssociationSetMapping 中有两个 EndProperty 
   EndProperty 
                                     分别对应 CSDL 中两个 End Role 

   Name                              EndProperty 的名称 

      ScalarProperty                 关系属性对应 

      Name                           CSDL 中的属性名 

      ColumnName                     SSDL 中的字段名称 

   ModificationFunctionMapping  C/D 对应的存储过程
InsertFunction/ DeleteFunction 

          FunctionName 

       QueryView 

                                               EntitySQL 

                                      用于描述 CSDL 与 SSDL 间函数及函数参数的对应(详见下文存储 
     FunctionImportMapping 
                                      过程部分) 




说明 1:以上表中很重要的一个属性是 MappingFragment 中的 StoreEntitySet 属性,就像这个属性的说明 
中所说,其描述了 CSDL 的 Entity 对应到的 SSDL 的 Entity 的名称。这是实现下文 EDM 映射方案中第二 
条将一个概念模型的实体映射到多个存储模型的实体的关键设置。 

说明 2:Contain 这个元素及其属性的作用是,当多个概念模型实体映射到一个存储模型实体时,该元素的 
属性决定了在什么情况下一个概念模型实体映射到指定的存储模型实体。 

说明 3:QueryView  元素定义概念模型中的实体与存储模型中的实体之间的只读映射。使用根据存储模型 
计算的  Entity  SQL  查询定义此查询视图映射,并以概念模型中的实体表达结果集。同 DefiningQuery 定 
义的查询。此映射也是只读的。就是说如果想要更新此类 EntitySet,也需要使用下文介绍存储过程时提到 
的定义更新实体的存储过程的方法,使用定义的存储过程来更新这样的 EntitySet。当多对多关联在存储模 
型中所映射到的实体表示关系架构中的链接表时,必须为此链接表在 AssociationSetMapping  元素中定义 
一个 QueryView 元素。定义查询视图时,不能在  AssociactionSetMapping  元素上指定  StorageSetName 
属性。定义查询视图时,AssociationSetMapping  元素不能同时包含  EndProperty  映射。 


EDM 中存储过程的设计 

目前版本(VS2008SP1)的实体设计器对存储过程支持不完善, 
                                只能手工编辑这三个文件中的存储过程部分, 
包括:


 ·        CSDL 中的 FunctionImport 元素,其属性及说明如下所示: 


          FunctionImport 

          Name                    (在程序中调用的)函数的名称 

          EntitySet               当函数返回实体对象时,需使用此属性指定对应的 EntitySet 

          ReturnType              函数返回值的类型 

                  Parameter       以下用于参数子节点中的属性定义 

                  Name            参数的名称 

                  Type            参数的类型
Mode            参数的传递方式(In, Out 或 InOut) 

                     MaxLength       参数值最大长度 

                     Precision       参数值的精确度,用于数字类型 

                     Scale           浮点数小数位



 ·        SSDL 中的 Function 节 


          Function 

          Name                               存储过程名称 

          Aggregate                          是否为聚合函数(存储过程) 

          BuiltIn                            是否为内建存储过程 

          NiladicFunction                    是否为无参数存储过程 

          IsComposable                       True 为自定义函数,False 为存储过程 

          ParameterTypeSemantics             参数类型转换方式 

          ReturnType                         存储过程返回类型



 ·        MSL 中的 FunctionImportMapping 节 


               FunctionImportMapping 

               FunctionImportName             CSDL 中 FunctionImport 的名称 

               FunctionName                   SSDL 中 Function Element 的名称

       · 这面总结的是用于返回实体对象的查询(存储过程)。 

下面分别描述一下有关修改操作的存储过程的使用:


 ·        使用插入、更新或删除实体数据的存储过程,需要修改如下两个文件: 

       SSDL,对其的修改要求与上文表中列出的一致: 


       MSL,需要对一下节点进行定义: 

EntityContainerMapping 

     EntitySetMapping                     EntityContainer 中每个 EntitySet 的对应 

        EntityTypeMapping                 描述 CSDL 中 EntityType 与 SSDL 中 EntityType 的对应 

           ModificationFunctionMapping    CUD 对应的存储过程
InsertFunction/ UpdateFunction / DeleteFunction 

                 FunctionName




 ·           使用创建或删除在数据源中使用链接表实现的实体类型之间的多对多关系的存储过程需要修改如 

       下两个文件: 
       SSDL,对其的修改要求与上文表中列出的一致: 


       MSL,需要对一下节点进行定义: 

EntityContainerMapping 

                                       描述 CSDL 中的 AssociationSet 与 SSDL 中的 EntitySet 的对应关 
     AssociationSetMapping 
                                       系 

        ModificationFunctionMapping  C/D 对应的存储过程 

              InsertFunction/ DeleteFunction 

              FunctionName 




EDM 中 ComplexType 的设计 

再谈 Complex  Type,上文大致介绍了复杂类型的概念及作用,现在开始看一下具体怎样实现。前文已经 
提到实现复杂类型关键是在 CSDL 与 MSL,而与 SSDL 无关。 

  首先应该在 CSDL 中怎加这样一节,此节与<EntityType></EntityType>节同级,其结构如下: 

<ComplexType> 

<Property /> 

</ComplexType> 

节点及其属性含义如下: 

ComplexType        复杂类型 

Name               复杂类型的名称 

     Property      属性 

     Name          属性名 

     Type          属性类型 

     Nullable      是否允许 null
MaxLength  属性最大长度 

     FixLength    是否固定长度 

     然后在 MSL 中<MappingFragment>下与<ScalarProperty  />同级的位置添加如下节: 

<ComplexProperty> 

<ScalarProperty /> 

</ComplexProperty> 

具体的节及其属性含义如下: 

ComplexProperty       复杂类型属性 

Name                  复杂类型属性名称 

                      CSDL 中定义的 ComplexType 的名称。格式 
TypeName 
                      "CSDN_Namespace.ComplexTypeName" 

     ScalarProperty  关系属性对应 

     Name             CSDL 中的属性名 

     ColumnName       SSDL 中的字段名称 




实体数据模型映射方案 

实体框架支持各种方式用于在实体数据模型  (EDM)  中将概念模型映射到关系数据。有关更多信息,请参 
见  实体框架中的数据建模。 

实体框架当前支持以下实体数据模型  (EDM)  映射方案。 

编
号      映射方案              说明 

                         在此映射方案中,概念模型中的每个实体都映射到存储模型中的单个表。这是实 
1      简单映射 
                         体数据模型工具所生成的默认映射。 

                         在此映射方案中,概念模型中单个实体的属性映射到两个或更多基础表中的列。 
2      实体拆分              在此方案中,表必须共享公共主键。 

                         其设计方式见 EDM 之 MSL 部分说明 1。 

                         在此映射方案中, 
                                 概念模型中的单个实体类型映射到具有相同架构的两个或更多 

       存储模型中的水           表。实体基于概念模型中定义的条件映射到表中。 
3 
       平分区               使用场合:使一个概念模型的实体映射到不同数据源的存储模型的实体。 

                         另见:EDM 之 MSL 部分说明 2。
在此映射方案中,概念模型中具有相同属性的多个实体类型映射到同一个表。条 
      概念模型中的水           件子句用于指定表中的数据分别属于哪个实体类型。此映射类似于类型 5。 
4 
      平分区               这种方式也用到 MSL 中的 Conditon 来决定映射关系,见 EDM 之 MSL 部分说 
                        明 2。 

                        在此映射方案中,继承层次结构中的所有类型都映射到同一个表。条件子句用于 
      每个层次结构一 
5                       定义实体类型。 
      个表继承 
                        见 EDM 之 MSL 部分说明 2。 

      每种类型一个表           在此映射方案中,所有类型都分别映射到各自的表。仅属于某个基类型或派生类 
6 
      继承                型的属性存储在映射到该类型的一个表中。 

      每种具体类型一           在此映射方案中,每个非抽象类型分别映射到不同的表。所有这些表所包含的列 
7 
      个表继承              必须映射到派生类型的所有属性(包括从基类型继承的属性)。 

                        在此映射方案中, 
                                单个实体类型在概念模型中以两个或更多独立的实体集进行表 
      每种类型多个实 
8                       示。每个实体集分别映射到存储模型中的一个单独的表。 
      体集 
                        其设计方式见 EDM 之 MSL 部分说明 1。 

                        复杂类型是没有键属性的实体类型的非标量属性。 
                                              复杂类型可以包含其他嵌套的 
9     复杂类型              复杂类型。复杂类型映射到存储模型中的表。 

                        复杂类型在上文有单独介绍 

                        在此方案中,存储模型中的存储过程映射到概念模型中的  FunctionImport  元 
10    函数导入映射            素。执行此函数可使用映射的存储过程返回实体数据。 

                        见上文存储过程部分 

                        在此方案中,在存储模型中定义用于插入、更新和删除数据的存储过程。这些函 
11    修改函数映射            数是为实体类型定义的,以便为特定实体类型提供更新功能。 

                        见上文存储过程部分 

                        在此方案中,在存储模型中定义表示数据源中的表的查询。在映射到  SQL 
                        Server  数据库时,查询以数据源的本机查询语言(如  Transact­SQL)表示。 
12    定义查询映射            此  DefiningQuery  元素映射到概念模型中的实体类型。查询以特定于存储的查 
                        询语言进行定义。 

                        上文 EDM 之 SSDL 部分最后详细介绍了这种设计的相关问题 

                        在此方案中, 
                              会在概念模型中的实体类型与存储模型中的关系表之间定义只读映 
13    查询视图映射            射。此映射基于对存储模型进行的  Entity SQL  查询定义。 

                        上文 EDM 之 MSL 中说明三对这种设计的相关问题有介绍。 

                        关联定义实体之间的关系。在具有一对一或一对多关联的简单映射中,在概念模 
                        型中定义关系的关联会映射到存储模型中的关联。 
                                              还支持以下更高级的关联集映 
      AssociationSet 
14                      射: 
      映射 
                        多对多关联。关联的两端都映射到存储模型中的链接表。 

                        自关联。 
                            此映射支持具有相同类型的两个实体之间的关联, 
                                                  如一个  Employee  与
另一个  Employee  之间的关联。 

                              派生类型之间的关联。 
                                        此映射支持一个层次结构中的派生类型与另一个层次结构 
                              中的派生类型之间的关联。 




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)


 ·        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(); 

}




     ·    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); 

}




     ·    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 方法传入的是一个 La 
mbda 表达式,你也可以传入一条 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 可能是最好的选择。


 ·      动态构建查询条件 

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


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

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

 ·      数据库模糊查询 


     下面代码演示使用 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 的工具,但其与强类型的 LIN 
Q  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(EntityType  entity) 

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

      entities.AddObject("EntitySetName",  entity); 

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

      entites.DeleteObject(object  o); 

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




    含有 Association 的 EDM 的使用 

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


     ·       显示加载 

          实体框架针对  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); 

} 

}


     ·    预先加载 


         先看代码示例 

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 来遍历需要删除的关系实体。取 
而代之的有两种方法:


     ·        while 法 


while  (result.Order_Details.Count  >  0) 

{ 

//  删除操作… 

}


     ·        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 控件也是很简单的。这源于使用 ObjectCo 
ntext 操作返回的 IQueryable<T>对象或是使用 EntityClient 查询返回的 ObjectQuery 对象都实现了 IEnum 
erable 接口。这样很容易将这些数据绑定到数据显示控件。更新操作可以按上文所述在相应的时间处理函 
数中写更新 EDM 的程序即可。 


Entity  Framework 的链接字符串 

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

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


本文来源: 
http://www.cnblogs.com/lsxqw2004/archive/2009/05/31/1495240.html#_Toc228672774

More Related Content

Viewers also liked

Photoscape
PhotoscapePhotoscape
Photoscapethamtip
 
Shannon elari
Shannon elariShannon elari
Shannon elari
selari
 
Coaching kippsters to guided reading success
Coaching kippsters to guided reading successCoaching kippsters to guided reading success
Coaching kippsters to guided reading success
bvardiman
 
Car project
Car projectCar project
Car project
selari
 
Circuit Vietnam à la folie
Circuit Vietnam à la folie Circuit Vietnam à la folie
Circuit Vietnam à la folie
Circuit Vietnam à la folie
 
Social Media Nut NO.1
Social Media Nut NO.1Social Media Nut NO.1
Social Media Nut NO.1Laura
 

Viewers also liked (6)

Photoscape
PhotoscapePhotoscape
Photoscape
 
Shannon elari
Shannon elariShannon elari
Shannon elari
 
Coaching kippsters to guided reading success
Coaching kippsters to guided reading successCoaching kippsters to guided reading success
Coaching kippsters to guided reading success
 
Car project
Car projectCar project
Car project
 
Circuit Vietnam à la folie
Circuit Vietnam à la folie Circuit Vietnam à la folie
Circuit Vietnam à la folie
 
Social Media Nut NO.1
Social Media Nut NO.1Social Media Nut NO.1
Social Media Nut NO.1
 

Similar to Entity+framework+

ADO.NET Entity Framework 4
ADO.NET Entity Framework 4ADO.NET Entity Framework 4
ADO.NET Entity Framework 4Raffaele Fanizzi
 
Architecture related with Zend Framework (Japanese only)
Architecture related with Zend Framework (Japanese only)Architecture related with Zend Framework (Japanese only)
Architecture related with Zend Framework (Japanese only)
T K
 
03 3-create-db-application-ado-dot-net Create Database Application with using...
03 3-create-db-application-ado-dot-net Create Database Application with using...03 3-create-db-application-ado-dot-net Create Database Application with using...
03 3-create-db-application-ado-dot-net Create Database Application with using...Warawut
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
deer hope
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程deer hope
 
2010 06 15 SecondNug - JAVA vs NET
2010 06 15 SecondNug - JAVA vs NET2010 06 15 SecondNug - JAVA vs NET
2010 06 15 SecondNug - JAVA vs NETBruno Capuano
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储
zhen chen
 
Lecture1
Lecture1Lecture1
Lecture1orgil
 
04 practical symfony 4дөх
04 practical symfony 4дөх04 practical symfony 4дөх
04 practical symfony 4дөхtuvshinmgl
 
第2章 asp
第2章  asp第2章  asp
第2章 asp
billao
 
VENU_Hadoop_Resume
VENU_Hadoop_ResumeVENU_Hadoop_Resume
VENU_Hadoop_ResumeVenu Gopal
 
Lecture16
Lecture16Lecture16
Lecture16orgil
 
Seguridad en Servicios Web
Seguridad en Servicios WebSeguridad en Servicios Web
Seguridad en Servicios Web
Hacking Bolivia
 
夜宴13期《事件驱动》
夜宴13期《事件驱动》夜宴13期《事件驱动》
夜宴13期《事件驱动》Koubei Banquet
 
Türsteher für Bohnen
Türsteher für BohnenTürsteher für Bohnen
Türsteher für Bohnen
Zambrovski Simon
 
Qt编程介绍
Qt编程介绍Qt编程介绍
Qt编程介绍
easychen
 
Lecture6
Lecture6Lecture6
Lecture6orgil
 
第3章 sql server 简介
第3章   sql server 简介第3章   sql server 简介
第3章 sql server 简介hanmo1988
 

Similar to Entity+framework+ (20)

ADO.NET Entity Framework 4
ADO.NET Entity Framework 4ADO.NET Entity Framework 4
ADO.NET Entity Framework 4
 
Architecture related with Zend Framework (Japanese only)
Architecture related with Zend Framework (Japanese only)Architecture related with Zend Framework (Japanese only)
Architecture related with Zend Framework (Japanese only)
 
03 3-create-db-application-ado-dot-net Create Database Application with using...
03 3-create-db-application-ado-dot-net Create Database Application with using...03 3-create-db-application-ado-dot-net Create Database Application with using...
03 3-create-db-application-ado-dot-net Create Database Application with using...
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
 
2010 06 15 SecondNug - JAVA vs NET
2010 06 15 SecondNug - JAVA vs NET2010 06 15 SecondNug - JAVA vs NET
2010 06 15 SecondNug - JAVA vs NET
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储
 
Lecture1
Lecture1Lecture1
Lecture1
 
04 practical symfony 4дөх
04 practical symfony 4дөх04 practical symfony 4дөх
04 practical symfony 4дөх
 
第2章 asp
第2章  asp第2章  asp
第2章 asp
 
VENU_Hadoop_Resume
VENU_Hadoop_ResumeVENU_Hadoop_Resume
VENU_Hadoop_Resume
 
Lecture16
Lecture16Lecture16
Lecture16
 
Seguridad en Servicios Web
Seguridad en Servicios WebSeguridad en Servicios Web
Seguridad en Servicios Web
 
夜宴13期《事件驱动》
夜宴13期《事件驱动》夜宴13期《事件驱动》
夜宴13期《事件驱动》
 
Türsteher für Bohnen
Türsteher für BohnenTürsteher für Bohnen
Türsteher für Bohnen
 
Qt编程介绍
Qt编程介绍Qt编程介绍
Qt编程介绍
 
Lecture6
Lecture6Lecture6
Lecture6
 
第3章 sql server 简介
第3章   sql server 简介第3章   sql server 简介
第3章 sql server 简介
 
MS Swit 2010
MS Swit 2010MS Swit 2010
MS Swit 2010
 
Resume Kankeyan
Resume KankeyanResume Kankeyan
Resume Kankeyan
 

Entity+framework+

  • 1. 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  Entity  Framework 的核心  –  EDM(Entity  Data  Model)  7  EDM 概述  7  EDM 之 CSDL  7  EDM 之 SSDL  11  EDM 之 MSL  12  EDM 中存储过程的设计  15  EDM 中 ComplexType 的设计  16  实体数据模型映射方案  17  Entity  Framework 的原理及使用方式  18  各种使用方式总结  18  使用技巧及需要注意的问题  21  几种方法的性能分析及使用选择  21  其它操作 EDM 的方式  22  为什么要使用 Entity  Framework,限制条件及当前版本框架的问题  23
  • 2. EDM 中的 DML  23  含有 Association 的 EDM 的使用  23  本文档主要介绍.NET 开发中两项新技术,.NET 平台语言中的语言集成查询技术  ­  LINQ,与 ADO.NET  中新增的数据访问层设计技术 ADO.NET  Entity  Framework。ADO.NET 的 LINQ  to  Entity 部分以 LINQ  为基础,为了完整性本文档首先介绍 LINQ 技术。  预备知识  LINQ 技术  LINQ 是.NET  3.5 中新增的一种技术,这个技术扩展了.NET 平台上的编程语言,使其可以更加方便的进行  数据查询,单纯的 LINQ 技术主要完成对集合对象(如 System.Collection 下或 System.Collection.Generi  c 命名空间下的对象)的查询。结合 LINQ  Provider 可以实现对 XML 文件(使用 LINQ  to  XML  –  位于 S  ystem.Xml.Linq 命名空间下的类),数据库(可以使用 LINQ  to  SQL 或下文要详细介绍的 LINQ  to  Entit  y)等对象的操作。  LINQ 是一种运行时无关的技术,其运行于 CLR2.0 之上,微软对 C#3.0 与 VB9.0 的编译器进性扩展,从  而使其可以将 LINQ 编写的程序编译为可以被 CLR2.0 的 JIT 所理解的 MSIL。  LINQ 技术的基础  ­  C#3.0 · 自动属性 · 隐式类型 · 对象集合初始化器 · 匿名类 · 扩展方法 · Lambda 表达式  自动属性
  • 3. 这个概念很简单,其简化了我们在.NET 的时候手写一堆私有成员+属性的编程方式,我们只需要使用如下  方式声明一个属性,编译器会自动生成所需的成员变量。  public  class  Customer  {  public  int  Id  {  get;  set;  }  public  string  Name  {  get;  set;  }  }  在我使用 LINQ 完成的项目中,使我了解到自动属性方便的一个用途如下:  在使用 LINQ 获取数据的过程中,我们常常需要使用 select  new 语句查询出一个对象(往往是 IEnumer  able 类型的)用于数据绑定。在一般情况下如果是直接绑定(如直接将查询结果赋给一个 Gridview 控件的  DataSource 属性)我们可以直接 select  new 来返回一个匿名类的对象。如果我们还需要对这个集合对象  进行进一步操作,我们将必须使用 select  new  class­name 这样的语言返回一个类的对象,大部分情况下  这个类只作为实体的一个结构而不需要完成一些操作操作,这时候使用自动属性来完成这个类将是非常简  洁高效的。  隐式类型  这个名称可能对你很陌生,但是 var 这个关键字应该都用过,在 C#中使用 var 声明一个对象时,编译器会  自动根据其赋值语句推断这个局部变量的类型。赋值以后,这个变量的类型也就确定而不可以再进行更改。  另外 var 关键字也用于匿名类的声明。  应用场合:var 主要用途是表示一个 LINQ 查询的结果。这个结果可能是 ObjectQuery<>或 IQueryable<  >类型的对象,也可能是一个简单的实体类型的对象。这时使用 var 声明这个对象可以节省很多代码书写上  的时间。  对象初始化器与集合初始化器  在.NET2.0 中构造一个对象的方法一是提供一个重载的构造函数,  二是用默认的构造函数生成一个对象,  然后对其属性进行赋值。在.NET3.5/C#3.0 中我们有一种更好的方式来进行对象的初始化。那就是使用对  象初始化器。这个特性也是匿名类的一个基础,所以放在匿名类之前介绍。  还是那就话,好的代码强于注释,下面用几个代码段说明初始化器:  (代码出自:李永京的博客  http://lyj.cnblogs.com)  基本用法:  User  user  =  new  User  {  Id  =  1,  Name  =  "YJingLee",  Age  =  22  };  嵌套使用:  User  user  =  new  User  {
  • 4. Id  =  1,  Name  =  "YJingLee",  Age  =  22,  Address  =  new  Address  {  City  =  "NanJing",  Zip  =  21000  }  };  类似于对象初始化器初始化一个对象,集合初始化器初始化一个集合,一句话,有了它你就不用在将元  素通过 Add 逐个添加了。仍然给出代码示例:  基本使用:  List<int>  num  =  new  List<int>  {  0,  1,  2,  6,  7,  8,  9  };  结合对象初始化器,我们可以写出如下简洁的代码:  List<User>  user  =  new  List<User>{  new  User{Id=1,Name="YJingLee",Age=22},  new  User{Id=2,Name="XieQing",Age=25},  };  应用场合:  还是前文提到的 select  new  class­name 语法,后面可以直接接一个初始化器来将查询结果返回到这个  对象。  匿名类  有了前文初始化器的介绍,  匿名类就很简单了。  我们可以使用 new  {  object  initializer  }或 new[]{  object,  …}  来初始化一个匿名类或不确定类型的数组。匿名类的对象需要使用 var 关键字声明。示例代码:  var  p1  =  new  {  Id  =  1,  Name  =  "YJingLee",  Age  =  22  };  应用场合:  还是同上面的例子提到的当直接使用 select  new  {  object  initializer  }这样的语法就是将一个 LINQ 查询的  结果返回到一个匿名类中。  扩展方法
  • 5. 扩展方法是 C#中新增的很重要的特性之一。其对于 LINQ 的实现起着关键的作用。在.NET2.0 时代是没  有 LINQ 的,所以.NET2.0 以及之前版本中的集合类在设计的时候没有预留用于 LINQ 的方法。为了在不破  坏这个类现有封装的前提下又可以为其添加 LINQ 的支持就需要用到扩展方法。  扩展方法使用上类似于静态方法,但在本质上其是实例方法。这是由于.NET3.5 的运行环境仍然为 CLR  2.0 所以语言不可能做很大的变革,这一切都是语法糖。  下面仍然通过一段代码来说明扩展方法的实现:  (代码出自:李永京  http://lyj.cnblogs.com)  public  static  class  Extensions  {  public  static  bool  IsValidEmailAddress(this  string  s)  {  Regex  regex  =  new  Regex(@"^[w­.]+@([w­]+.)+[w­]{2,4}$");  return  regex.IsMatch(s);  }  }  如上代码所示,扩展方法为一静态方法,声明于一个静态类,其参数前加上一个 this 关键字,参数的类型  表示这个扩展方法要对这个类型进行扩展。如上述代码表示其要对字符串类型进行扩展。  在应用上扩展方法被作为其扩展的类型的静态方法来调用。如下:  if  (email.IsValidEmailAddress())  {  Response.Write("YJingLee 提示:这是一个正确的邮件地址");  }  Lambda 表达式  Lambda 表达式是对.NET2.0 中匿名方法在语法形式上的进一步改进,仍然以代码说明:  var  inString  =  list.FindAll(delegate(string  s)  {  return  s.Indexof("YJingLee")  >=  0;  });  使用 Lambda 表达式代码将更自然易懂。  var  inString  =  list.FindAll(s  =>  s.Indexof("YJingLee")  >=  0);  可以看出,Lambda 表达式格式为:(参数列表)=>表达式或语句块  “Lambda  表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类  型。
  • 6. 所有  Lambda  表达式都使用  Lambda  运算符  =>,该运算符读为“goes  to”。该  Lambda  运算符  的左边是输入参数(如果有),右边包含表达式或语句块。Lambda  表达式  x  =>  x  *  x  读作“x  goes  t  o  x  times  x”。可以将此表达式分配给委托类型,如下所示:  delegate  int  del(int  i);  del  myDelegate  =  x  =>  x  *  x;  int  j  =  myDelegate(5);  //j  =  25  创建表达式目录树类型:  using  System.Linq.Expressions;  //  ...  Expression<del>  =  x  =>  x  *  x;  =>  运算符具有与赋值运算符  (=)  相同的优先级,并且是右结合运算符。  Lambda  用在基于方法的  LINQ  查询中,作为诸如  Where  和  Where  等标准查询运算符方法的参  数。  使用基于方法的语法在  Enumerable  类中调用  Where  方法时  (像在  LINQ  to  Objects  和  LINQ  to  XML  中那样),参数是委托类型  System..::.Func<(Of  <(T,  TResult>)>)。使用  Lambda  表达式创建委  托最为方便。例如,当您在  System.Linq..::.Queryable  类中调用相同的方法时(像在  LINQ  to  SQL  中  那样),则参数类型是  System.Linq.Expressions..::.Expression<Func>,其中  Func  是包含至多五个输  入参数的任何  Func  委托。同样,Lambda  表达式只是一种用于构造表达式目录树的非常简练的方式。尽  管事实上通过  Lambda  创建的对象的类型是不同的,但  Lambda  使得  Where  调用看起来类似。  在前面的示例中,请注意委托签名具有一个  int  类型的隐式类型输入参数,并返回  int。可以将  Lam  bda  表达式转换为该类型的委托,因为该表达式也具有一个输入参数  (x),以及一个编译器可隐式转换为  int  类型的返回值。(以下几节中将对类型推理进行详细讨论。)使用输入参数  5  调用委托时,它将返回  结果  25。  在  is  或  as  运算符的左侧不允许使用  Lambda。  适用于匿名方法的所有限制也适用于  Lambda  表达式。有关更多信息,请参见匿名方法(C#  编程指  南)。 下列规则适用于  Lambda  表达式中的变量范围:  捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。  在外部方法中看不到  Lambda  表达式内引入的变量。  Lambda  表达式无法从封闭方法中直接捕获  ref  或  out  参数。  Lambda  表达式中的返回语句不会导致封闭方法返回。  Lambda  表达式不能包含其目标位于所包含匿名函数主体外部或内部的  goto  语句、break  语句或  c  ontinue  语句。  .NET 中的数据访问
  • 7. 这一部分介绍.NET 中不同的数据访问层的使用方式,  由此得出 Entity  Framework 在一个.NET 系统中的应  用及其在原有设计基础上的改变。从大的方面来看数据访问的设计方案基本有如下几类: · DataSet · 手写代码通过 ADO.NET2.0 连接类与数据库交互 · ORM 组件  DataSet 方案  最基本的 Dataset 数据访问的实现使用下图表示:  图 1  如图所示,DataSet 与数据源之间通过 DataAdapter 连接,逻辑中直接访问 DataSet 获取数据,或是通过  ADO.NET2.0 的非连接类,或者通过强类型 DataSet 以一种类型安全的方式访问数据。  缺点逻辑代码与数据访问代码耦合高。  改进的的 DataSet 方案  图2
  • 8. 这种设计方式将业务所需的实体抽象出来,并把对 DataSet 的操作封装在其中,这样一定程序上解除业务  逻辑与数据访问间的耦合。  手写代码通过 ADO.NET2.0 连接类与数据库交互  这种方式是我使用的最多的一种方式,其可以提供最大的控制能力,且效率最高,唯一的不足是当业务变  化时修改数据访问代码的工作量比较大,通过代码生成器也能一定程度上解决这个问题  ORM  –  LINQ  to  SQL  在.NET 平台下 ORM 的解决方案有不少,本文只讨论两个微软官方的解决方案。先是 LINQ  to  SQL 技术。  LINQ  to  SQL 是一个将不再更新的技术。其有很多不足之处,如,不能灵活的定义对象模型与数据表之间  的映射、无法扩展提供程序只能支持 SQL  Server 等。  这样数据访问层的设计如下所示:  图 3  ORM  –  ADO.NET  Entity  Framework  作为下一代数据访问的技术领导者。Entity  Framework 的设计很多地方都保留了高扩展性。其最重要的一  个改进在于其映射定义的灵活性。先来看下图:
  • 9. 图 4  由图可以看出,使用 Entity  Framework 可以充分的定义与数据库表映射的实体,并将这个实体直接用于业  务逻辑层或作为服务的数据契约。实体设计较其他技术的优势体现在以下几方面: · 创建 ComplexType(CSDL 部分有讨论) · EntitySet 的继承  使用 Entity  Framework 后,可以将实体类的设计工作完全放在 EDM 的设计过程中,而不再需要手工写一  些大同小异的代码,并且对这个实体模型(包含于 EDM 中)可以在运行时修改并生效。另外,开发人员  与数据库直接打交道的次数将大大减少,大部分时间开发人员只需操作实体模型,框架会自动完成对数据  库的操作。下文将详细讨论上图所示的 EDM。  深入了解 Entity  Framework  Entity  Framework 的核心  –  EDM(Entity  Data  Model)  EDM 概述  实体数据模型,简称 EDM,由三个概念组成。概念模型由概念架构定义语言文件  (.csdl)来定义,映射由  映射规范语言文件  (.msl),存储模型(又称逻辑模型)由存储架构定义语言文件  (.ssdl)来定义。这三者合  在一起就是 EDM 模式。EDM 模式在项目中的表现形式就是扩展名为.edmx 的文件。这个包含 EDM 的文  件可以使用 Visual  Studio 中的 EDM 设计器来设计。由于这个文件本质是一个 xml 文件,可以手工编辑此  文件来自定义 CSDL、MSL 与 SSDL 这三部分。下面详细分析一下这个 xml 文件及三个其重要组成部分:  这个文件展示了示例项目完整的 EDM 文件的 XML 形式:  文件  这个设计器生成的文件的注释可以使你很清楚的明白这个 EDM 文件的组成。一点点分析一下,第一行表  明这是一个 xml 文件。
  • 10. <?xml version="1.0" encoding="utf­8"?>  以下这一行是 EDM 的根节点,定义了一个表明版本的属性及这个 EDM 使用的命名空间:  <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">  接下来由注释可以看到 EDM 被分为两部分,第一部分是 EDM 的核心,第二部分用于实体设计器,这一部  分不用研究。  第一部分中节点<edmx:Runtime>下定义了以下三部分:  EDM 之 CSDL  CSDL 定义了 EDM 或者说是整个程序的灵魂部分  –  概念模型。  当前流行的软件设计方法通常都是由设  计其概念模型起步。说概念模型可能比较抽象一个更容易接受的名字就是实体类。实体类是面向对象设计  中一个最根本的组成部分,其体现了现实世界中对象作为一种计算中可以表示的对象设计方法。而 EDM  的 CSDL 就是要达到这样一个目的。这个在下文介绍 Entity  Framework 优点时另有说明。  这个文件完全以程序语言的角度来定义模型的概念。即其中定义的实体、主键、属性、关联等都是对应  于.NET  Framework 中的类型。下面 xml  element 来自作业提交系统(有删节):  <!­­ CSDL content ­­>  <edmx:ConceptualModels>  <Schema Namespace="ASSModel" Alias="Self"  xmlns="http://schemas.microsoft.com/ado/2006/04/edm">  <EntityContainer Name="ASSEntities">  <FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments"  ReturnType="Collection(Self.UpAssignments)">  <Parameter Name="StuID" Type="Int32" Mode="In" />  <Parameter Name="ClassID" Type="Int32" Mode="In" />  <Parameter Name="Semester" Type="String" Mode="In" />  </FunctionImport>  <!­­  以上删节  – 5 个存储过程  ­­>  <EntitySet Name="Assignments" EntityType="ASSModel.Assignments" />  <EntitySet Name="Classes" EntityType="ASSModel.Classes" />  <EntitySet Name="Courses" EntityType="ASSModel.Courses" />  <EntitySet Name="SetCourses" EntityType="ASSModel.SetCourses" />  <EntitySet Name="Students" EntityType="ASSModel.Students" />  <EntitySet Name="Teachers" EntityType="ASSModel.Teachers" />  <EntitySet Name="UpAssignments" EntityType="ASSModel.UpAssignments" />
  • 11. <AssociationSet Name="FK_SetCourses_Classes" Association="ASSModel.FK_SetCourses_Classes">  <End Role="Classes" EntitySet="Classes" />  <End Role="SetCourses" EntitySet="SetCourses" />  </AssociationSet>  <!­­  以上删节  – 6 个关系集  ­­>  </EntityContainer>  <!­­  以下保留一个 EntityType 作为示例  ­­>  <EntityType Name="Students">  <Key>  <PropertyRef Name="StuID" />  </Key>  <Property Name="StuID" Type="Int32" Nullable="false" />  <Property Name="StuName" Type="String" Nullable="false" MaxLength="10" Unicode="true"  FixedLength="true" />  <Property Name="Pswd" Type="String" Nullable="false" MaxLength="50" Unicode="false"  FixedLength="true" />  <NavigationProperty Name="Classes" Relationship="ASSModel.FK_Students_Classes"  FromRole="Students" ToRole="Classes" />  <NavigationProperty Name="UpAssignments" Relationship="ASSModel.FK_UpAssignments_Students"  FromRole="Students" ToRole="UpAssignments" />  </EntityType>  <!­­  仅保留与上文 AssociationSet 对应的 Association ­­>  <Association Name="FK_SetCourses_Classes">  <End Role="Classes" Type="ASSModel.Classes" Multiplicity="1" />  <End Role="SetCourses" Type="ASSModel.SetCourses" Multiplicity="*" />  </Association>  </Schema>  </edmx:ConceptualModels>  这部分 XML 文档,Schema 是 CSDL 的根元素,其中定义的 Namespace 是用于 ObjectContext 与 Entity  Class 的命名空间,Alias­别名为此命名空间 Namespace 指定一个易记的名称,在定义 Alias 之后,在此 S  chema 内的 Element 均可以该 Alias 作为 Namespace 的别名。Alias 的使用可以参考如下 xml  element:  <FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments"
  • 12. ReturnType="Collection(Self.UpAssignments)">  在这个根元素的内部的文档结构第一部分  –  实体容器大致如下:  <EntityContainer />  <FunctionImport />  <EntitySet />  <AssociationSet />  </EntityContainer>  下面的表格说明了这些节点及其属性的作用  EntityContainer  Name  EntityContainer 的名称,其将作为产生的 ObjectContext 类的名称  EntitySet  Name  ObjectContext 内与此 Entity 类型对应的属性名  EntityType  ObjectContext 内与此 Entity 类型对应的属性的类型  AssociationSet  End  有两个 End 子节点,分别描述建立此关系的两个 EntitySet  对应到 Association 中 End 节的 Role 属性,起到将 AssociationSet 与 Association  Role  相关连的作用。  FunctionImport  详见存储过程设计部分  可以看出,Entity 与 Assciation 都被分开定义与两个部分,这样设计是出于当有多个 EntityContainer 时,  其中的 EntitySet 或 AssociationSet 可以共享 Entity 或 Association 的定义。  接下来看一下 CSDL 中最后一部分,Entity 与 Association 的定义。  首先是 Entity:  <EntityType  Name="Students">  <Key>  <PropertyRef  Name="StuID"  />  </Key>  <Property  Name="StuID"  Type="Int32"  Nullable="false"  />  <Property  Name="StuName"  Type="String"  Nullable="false"  MaxLength="10"  Unicode="true"  FixedL  ength="true"  />  <Property  Name="Pswd"  Type="String"  Nullable="false"  MaxLength="50"  Unicode="false"  FixedLeng  th="true"  />
  • 13. <NavigationProperty  Name="Classes"  Relationship="ASSModel.FK_Students_Classes"  FromRole="St  udents"  ToRole="Classes"  />  <NavigationProperty  Name="UpAssignments"  Relationship="ASSModel.FK_UpAssignments_Students  "  FromRole="Students"  ToRole="UpAssignments"  />  </EntityType>  下表说明了其属性及其子节点与子节点的属性的含义:  EntityType  Name  Entity Class 的名称  Abstract  是否为抽象类  BaseType  父类  Key  主键  Property  主键之属性  Name  属性名  Property  属性  Name  属性名  Type  属性类型  Nullable  是否允许 null  MaxLength  属性最大长度  FixLength  是否固定长度  NavigationProperty  关系属性  Name  属性名  Relationship  对应的 Association  FromRole、ToRole  区别关系两方的父与子  最后 Association 节,这是真正定义关系的地方。首先看示例:  <!­­  仅保留与上文 AssociationSet 对应的 Association  ­­>  <Association  Name="FK_SetCourses_Classes">  <End  Role="Classes"  Type="ASSModel.Classes"  Multiplicity="1"  />  <End  Role="SetCourses"  Type="ASSModel.SetCourses"  Multiplicity="*"  />  </Association>
  • 14. 这一节符合以下结构:  <Association>  <End />  <ReferentialConstraint>  <Principal>  <PropertyRef />  </Principal>  <Dependent>  <PropertyRef />  </Dependent>  </ReferentialConstraint>  </Association>  属性及其子元素属性的说明:  Association  Name  Association 的名称  End  类似于 AssociationSet,Association 也有两个 End 节点。  Name  End 名称  Type  EntityType 的名称  Role  此 End 的 Role,与 AssociationSet 的 End 的 Role 属性相联系  Multiplicity  关联多重性,值为 0、1 或*  ReferentialConstraint  外键条件限制  Principal  主要条件  Role  对应于 End 中的 Role  PropertyRef  外键属性  Name  属性名称  Dependent  依存条件  Role  对应于 End 中的 Role  PropertyRef  外键属性  Name  属性名
  • 15. 另外上面示例未涉及的概念,如下:  视图  在 EDM 设计器中添加视图基本与添加实体表一致,所生成的 xml 自行对照。某些环境下可能无法添加  视图,原因未知,另外对于没有主键的表目前版本 EntityFramework 支持不好,在设计器中无法添加,及  时通过手工编辑 xml 的方式强行添加,在使用过程中也会出现问题。  ComplexType(复杂类型)  按 MSDN 中的例子,先描述如下场景。在一个销售系统中我们需要在一个订单中包含一个描述客户地址的  实体,而这个实体又能良好的与存储模型映射起来,由于数据库不支持地址这种类型,所以我们可以将地  址的每个字段与数据库相映射。且在概念模型中,及在 C#代码可以控制的范围内,地址仍然作为一个独立  的类型存在。由于 EDM 设计器不支持以可视化方式创建 Complex  Type,我们需要手动编辑 CSDL 与 MS  L 来完成复杂类型的创建与映射。这部分示例将在介绍 MSL 后给出。  EDM 之 SSDL  这个文件中描述了表、列、关系、主键及索引等数据库中存在的概念。  <!­­ SSDL content ­­>  <edmx:StorageModels>  <Schema Namespace="ASSModel.Store" Alias="Self" Provider="System.Data.SqlClient"  ProviderManifestToken="2008"  xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"  xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">  <EntityContainer Name="ASSModelStoreContainer">  <EntitySet Name="Assignments" EntityType="ASSModel.Store.Assignments" store:Type="Tables"  Schema="dbo" />  <!­­  省略 7 个 EntitySet 的定义  ­­>  </EntityContainer>  <!­­  以下省略 7 个 EntityType 的定义  ­­>  <EntityType Name="Assignments">  <Key>  <PropertyRef Name="AssID" />  </Key>  <Property Name="AssID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />  <Property Name="AssName" Type="nchar" Nullable="false" MaxLength="20" />
  • 16. <Property Name="AssDes" Type="nvarchar" MaxLength="500" />  <Property Name="SCID" Type="int" Nullable="false" />  <Property Name="Deadline" Type="datetime" Nullable="false" />  <Property Name="QuesFileName" Type="nvarchar" MaxLength="500" />  <Property Name="QuesFileUrl" Type="nvarchar" Nullable="false" MaxLength="500" />  </EntityType>  <!­­  保留与 CSDL 中对应的 Function ­­>  <Function Name="GETHOUSEWORKDONE" Aggregate="false" BuiltIn="false" NiladicFunction="false"  IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">  <Parameter Name="StuID" Type="int" Mode="In" />  <Parameter Name="ClassID" Type="int" Mode="In" />  <Parameter Name="Semester" Type="varchar" Mode="In" />  </Function>  </Schema>  </edmx:StorageModels>  看文档的结构,SSDL 与 CSDL 很详细,只是其中 EntityType 等使用数据库的概念的描述。  这其中有一个需要稍微介绍节点,DefiningQuery,首先看一下其出现的位置:  EntityContainer  EntitySet  DefiningQuery  通过查询定义一个 SSDL 的 EntitySet  特定于存储的查询语句  DefiningQuery 定义通过实体数据模型  (EDM)  内的客户端投影映射到数据存储视图的查询。  此类映射是只  读的。也就是说如果想要更新此类 EntitySet,需要使用下文介绍存储过程时提到的定义更新实体的存储过  程的方法,使用定义的存储过程来更新这样的 EntitySet。当在实体类设计器中导入无主键的表时,会自动  生成此类使用 DefiningQuery 定义的 EntitySet,要式样 Entity  Framework 提供的自动更新服务而不定义  存储过程,需要给数据表添加一个适当的主键,删除 DefiningQuery 节点并更新数据模型。  EDM 之 MSL  这个文件即上面所述的 CSDL 与 SSDL 的对应,主要包括 CSDL 中属性与 SSDL 中列的对应。  <!­­ C­S mapping content ­­>  <edmx:Mappings>
  • 17. <Mapping Space="C­S" xmlns="urn:schemas­microsoft­com:windows:storage:mapping:CS">  <EntityContainerMapping StorageEntityContainer="ASSModelStoreContainer"  CdmEntityContainer="ASSEntities">  <EntitySetMapping Name="Assignments">  <EntityTypeMapping TypeName="IsTypeOf(ASSModel.Assignments)">  <MappingFragment StoreEntitySet="Assignments">  <ScalarProperty Name="QuesFileName" ColumnName="QuesFileName" />  <ScalarProperty Name="AssDes" ColumnName="AssDes" />  <ScalarProperty Name="AssID" ColumnName="AssID" />  <ScalarProperty Name="AssName" ColumnName="AssName" />  <ScalarProperty Name="Deadline" ColumnName="Deadline" />  <ScalarProperty Name="QuesFileUrl" ColumnName="QuesFileUrl" />  </MappingFragment>  </EntityTypeMapping>  </EntitySetMapping>  <!­­  省略 EntitySetMapping 若干  ­­>  <!­­  保留对应于 CSDL 与 SSDL 的 FunctionImportMapping ­­>  <FunctionImportMapping FunctionImportName="GETHOUSEWORKDONE"  FunctionName="ASSModel.Store.GETHOUSEWORKDONE" />  <AssociationSetMapping Name="FK_UpAssignments_Assignments"  TypeName="ASSModel.FK_UpAssignments_Assignments" StoreEntitySet="UpAssignments">  <EndProperty Name="Assignments">  <ScalarProperty Name="AssID" ColumnName="AssID" />  </EndProperty>  <EndProperty Name="UpAssignments">  <ScalarProperty Name="UpAssID" ColumnName="UpAssID" />  </EndProperty>  </AssociationSetMapping>  <!­­  省略 AssociationSetMapping 若干  ­­>  </EntityContainerMapping>  </Mapping>  </edmx:Mappings>
  • 18. 如上代码所示,  MSL 的根节点为 Mapping,  其中可以包含多个 EntityContainerMapping  (上例只有一个),  每一个 EntityContainerMapping 对应着两个分别来自 CSDL 与 SSDL 的 EntityContainer。  这个 EntityCont  ainerMapping 就是描述这两个 EntityContainer 间的对应。下面再给出一段代码展示 EntityContainerMapp  ing 的基本格式。  <EntityContainerMapping StorageEntityContainer="" CdmEntityContainer="">  <EntitySetMapping>  <EntityTypeMapping>  <MappingFragment>  <ScalarProperty />  </MappingFragment>  <ModificationFunctionMapping>  <InsertFunction />  <DeleteFunction />  <UpdateFunction />  </ ModificationFunctionMapping>  </EntityTypeMapping>  </EntitySetMapping>  <AssociationSetMapping>  <EndProperty>  <ScalarProperty />  </EndProperty>  </AssociationSetMapping>  <FunctionImportMapping />  </EntityContainerMapping>  同上文,下面列出这些节点的属性  EntityContainerMapping  StorageEntityContainer  SSDL 中的 EntityContainer 名称  CdmEntityContainer  CSDL 中的 EntityContainer 名称  EntitySetMapping  EntityContainer 中每个 EntitySet 的对应  Name  EntitySetMapping 的名称  EntityTypeMapping  描述 CSDL 中 EntityType 与 SSDL 中 EntityType 的对应
  • 19. Name  EntityTypeMapping 的名称  对应 CSDL 内 Entity 的名称  –  格式:IsTypeOf(<名称>)  TypeName  注:这个类及其子类将共享此 EntityTypeMapping  MappingFragment  描述属性及字段间的对应  SSDL 中的 EntitySet 名称  StoreEntitySet  (由于 CSDL 中一个 EntitySet 可以对应多个 SSDL 中的 EntitySet)  ScalarProperty  属性与字段对应  Name  CSDL 中的属性名  ColumnName  SSDL 中的字段名称  Condition  详见说明 2  ColumnName  列名  Value  值  ModificationFunctionMapping  CUD 对应的存储过程  InsertFunction/ UpdateFunction / DeleteFunction  FunctionName  QueryView  Entity SQL  描述 CSDL 中的 AssociationSet 与 SSDL 中的 EntitySet 的对应关  AssociationSetMapping  系  Name  AssociationSetMapping 的名称  StoreEntitySet  SSDL 中 EntitySet 的名称  TypeName  CSDL 中 AssociationSet 的名称  一个 AssociationSetMapping 中有两个 EndProperty  EndProperty  分别对应 CSDL 中两个 End Role  Name  EndProperty 的名称  ScalarProperty  关系属性对应  Name  CSDL 中的属性名  ColumnName  SSDL 中的字段名称  ModificationFunctionMapping  C/D 对应的存储过程
  • 20. InsertFunction/ DeleteFunction  FunctionName  QueryView  EntitySQL  用于描述 CSDL 与 SSDL 间函数及函数参数的对应(详见下文存储  FunctionImportMapping  过程部分)  说明 1:以上表中很重要的一个属性是 MappingFragment 中的 StoreEntitySet 属性,就像这个属性的说明  中所说,其描述了 CSDL 的 Entity 对应到的 SSDL 的 Entity 的名称。这是实现下文 EDM 映射方案中第二  条将一个概念模型的实体映射到多个存储模型的实体的关键设置。  说明 2:Contain 这个元素及其属性的作用是,当多个概念模型实体映射到一个存储模型实体时,该元素的  属性决定了在什么情况下一个概念模型实体映射到指定的存储模型实体。  说明 3:QueryView  元素定义概念模型中的实体与存储模型中的实体之间的只读映射。使用根据存储模型  计算的  Entity  SQL  查询定义此查询视图映射,并以概念模型中的实体表达结果集。同 DefiningQuery 定  义的查询。此映射也是只读的。就是说如果想要更新此类 EntitySet,也需要使用下文介绍存储过程时提到  的定义更新实体的存储过程的方法,使用定义的存储过程来更新这样的 EntitySet。当多对多关联在存储模  型中所映射到的实体表示关系架构中的链接表时,必须为此链接表在 AssociationSetMapping  元素中定义  一个 QueryView 元素。定义查询视图时,不能在  AssociactionSetMapping  元素上指定  StorageSetName  属性。定义查询视图时,AssociationSetMapping  元素不能同时包含  EndProperty  映射。  EDM 中存储过程的设计  目前版本(VS2008SP1)的实体设计器对存储过程支持不完善,  只能手工编辑这三个文件中的存储过程部分,  包括: · CSDL 中的 FunctionImport 元素,其属性及说明如下所示:  FunctionImport  Name  (在程序中调用的)函数的名称  EntitySet  当函数返回实体对象时,需使用此属性指定对应的 EntitySet  ReturnType  函数返回值的类型  Parameter  以下用于参数子节点中的属性定义  Name  参数的名称  Type  参数的类型
  • 21. Mode  参数的传递方式(In, Out 或 InOut)  MaxLength  参数值最大长度  Precision  参数值的精确度,用于数字类型  Scale  浮点数小数位 · SSDL 中的 Function 节  Function  Name  存储过程名称  Aggregate  是否为聚合函数(存储过程)  BuiltIn  是否为内建存储过程  NiladicFunction  是否为无参数存储过程  IsComposable  True 为自定义函数,False 为存储过程  ParameterTypeSemantics  参数类型转换方式  ReturnType  存储过程返回类型 · MSL 中的 FunctionImportMapping 节  FunctionImportMapping  FunctionImportName  CSDL 中 FunctionImport 的名称  FunctionName  SSDL 中 Function Element 的名称 · 这面总结的是用于返回实体对象的查询(存储过程)。  下面分别描述一下有关修改操作的存储过程的使用: · 使用插入、更新或删除实体数据的存储过程,需要修改如下两个文件:  SSDL,对其的修改要求与上文表中列出的一致:  MSL,需要对一下节点进行定义:  EntityContainerMapping  EntitySetMapping  EntityContainer 中每个 EntitySet 的对应  EntityTypeMapping  描述 CSDL 中 EntityType 与 SSDL 中 EntityType 的对应  ModificationFunctionMapping  CUD 对应的存储过程
  • 22. InsertFunction/ UpdateFunction / DeleteFunction  FunctionName · 使用创建或删除在数据源中使用链接表实现的实体类型之间的多对多关系的存储过程需要修改如  下两个文件:  SSDL,对其的修改要求与上文表中列出的一致:  MSL,需要对一下节点进行定义:  EntityContainerMapping  描述 CSDL 中的 AssociationSet 与 SSDL 中的 EntitySet 的对应关  AssociationSetMapping  系  ModificationFunctionMapping  C/D 对应的存储过程  InsertFunction/ DeleteFunction  FunctionName  EDM 中 ComplexType 的设计  再谈 Complex  Type,上文大致介绍了复杂类型的概念及作用,现在开始看一下具体怎样实现。前文已经  提到实现复杂类型关键是在 CSDL 与 MSL,而与 SSDL 无关。  首先应该在 CSDL 中怎加这样一节,此节与<EntityType></EntityType>节同级,其结构如下:  <ComplexType>  <Property />  </ComplexType>  节点及其属性含义如下:  ComplexType  复杂类型  Name  复杂类型的名称  Property  属性  Name  属性名  Type  属性类型  Nullable  是否允许 null
  • 23. MaxLength  属性最大长度  FixLength  是否固定长度  然后在 MSL 中<MappingFragment>下与<ScalarProperty  />同级的位置添加如下节:  <ComplexProperty>  <ScalarProperty />  </ComplexProperty>  具体的节及其属性含义如下:  ComplexProperty  复杂类型属性  Name  复杂类型属性名称  CSDL 中定义的 ComplexType 的名称。格式  TypeName  "CSDN_Namespace.ComplexTypeName"  ScalarProperty  关系属性对应  Name  CSDL 中的属性名  ColumnName  SSDL 中的字段名称  实体数据模型映射方案  实体框架支持各种方式用于在实体数据模型  (EDM)  中将概念模型映射到关系数据。有关更多信息,请参  见  实体框架中的数据建模。  实体框架当前支持以下实体数据模型  (EDM)  映射方案。  编 号  映射方案  说明  在此映射方案中,概念模型中的每个实体都映射到存储模型中的单个表。这是实  1  简单映射  体数据模型工具所生成的默认映射。  在此映射方案中,概念模型中单个实体的属性映射到两个或更多基础表中的列。  2  实体拆分  在此方案中,表必须共享公共主键。  其设计方式见 EDM 之 MSL 部分说明 1。  在此映射方案中,  概念模型中的单个实体类型映射到具有相同架构的两个或更多  存储模型中的水  表。实体基于概念模型中定义的条件映射到表中。  3  平分区  使用场合:使一个概念模型的实体映射到不同数据源的存储模型的实体。  另见:EDM 之 MSL 部分说明 2。
  • 24. 在此映射方案中,概念模型中具有相同属性的多个实体类型映射到同一个表。条  概念模型中的水  件子句用于指定表中的数据分别属于哪个实体类型。此映射类似于类型 5。  4  平分区  这种方式也用到 MSL 中的 Conditon 来决定映射关系,见 EDM 之 MSL 部分说  明 2。  在此映射方案中,继承层次结构中的所有类型都映射到同一个表。条件子句用于  每个层次结构一  5  定义实体类型。  个表继承  见 EDM 之 MSL 部分说明 2。  每种类型一个表  在此映射方案中,所有类型都分别映射到各自的表。仅属于某个基类型或派生类  6  继承  型的属性存储在映射到该类型的一个表中。  每种具体类型一  在此映射方案中,每个非抽象类型分别映射到不同的表。所有这些表所包含的列  7  个表继承  必须映射到派生类型的所有属性(包括从基类型继承的属性)。  在此映射方案中,  单个实体类型在概念模型中以两个或更多独立的实体集进行表  每种类型多个实  8  示。每个实体集分别映射到存储模型中的一个单独的表。  体集  其设计方式见 EDM 之 MSL 部分说明 1。  复杂类型是没有键属性的实体类型的非标量属性。  复杂类型可以包含其他嵌套的  9  复杂类型  复杂类型。复杂类型映射到存储模型中的表。  复杂类型在上文有单独介绍  在此方案中,存储模型中的存储过程映射到概念模型中的  FunctionImport  元  10  函数导入映射  素。执行此函数可使用映射的存储过程返回实体数据。  见上文存储过程部分  在此方案中,在存储模型中定义用于插入、更新和删除数据的存储过程。这些函  11  修改函数映射  数是为实体类型定义的,以便为特定实体类型提供更新功能。  见上文存储过程部分  在此方案中,在存储模型中定义表示数据源中的表的查询。在映射到  SQL  Server  数据库时,查询以数据源的本机查询语言(如  Transact­SQL)表示。  12  定义查询映射  此  DefiningQuery  元素映射到概念模型中的实体类型。查询以特定于存储的查  询语言进行定义。  上文 EDM 之 SSDL 部分最后详细介绍了这种设计的相关问题  在此方案中,  会在概念模型中的实体类型与存储模型中的关系表之间定义只读映  13  查询视图映射  射。此映射基于对存储模型进行的  Entity SQL  查询定义。  上文 EDM 之 MSL 中说明三对这种设计的相关问题有介绍。  关联定义实体之间的关系。在具有一对一或一对多关联的简单映射中,在概念模  型中定义关系的关联会映射到存储模型中的关联。  还支持以下更高级的关联集映  AssociationSet  14  射:  映射  多对多关联。关联的两端都映射到存储模型中的链接表。  自关联。  此映射支持具有相同类型的两个实体之间的关联,  如一个  Employee  与
  • 25. 另一个  Employee  之间的关联。  派生类型之间的关联。  此映射支持一个层次结构中的派生类型与另一个层次结构  中的派生类型之间的关联。  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) · EntityClient+EntitySQL  示例代码:  string  city  =  "London";  using  (EntityConnection  cn  =  new  EntityConnection("Name=Entities"))
  • 26. {  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();  } · 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);  } · ObjectContext+LINQ(  to  Entity)
  • 27. 方式一:  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 方法传入的是一个 La  mbda 表达式,你也可以传入一条 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);  }
  • 28. 使用技巧及需要注意的问题  这也是上文提到的在 ObjectContext 下使用 EntitySQL 的一个主要作用,上面的例子比较简单可能看不到  这样使用的优势,但是如下两种情况下使用 EntitySQL 可能是最好的选择。 · 动态构建查询条件  当查询条件的个数固定时,我们也可以采用罗列多个 Where 扩展方法的形式,如下:  ObjectQuery.Where(LambdaExpression1) .Where(LambdaExpression2)… · 但是当这个条件的存在与否需要在运行时判断时,我们只能通过组合字符串来得到这个条件,我  们可以将条件组合为 EntitySQL 并传递给 Where()方法。 · 数据库模糊查询  下面代码演示使用 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。这
  • 29. 样来看使用 LINQ  to  Entity 与 Entity  SQL 的效率应该差不多,但是还有一个问题,那就是 EntitySQL 所  转换的最终 SQL 可能要比 LINQ  to  Entity 生成的 SQL 效率高,这在一定程度上使两者效率差增大,但是  LINQ  to  Entity 有其它技术无法比拟的好处,那就是它的强类型特性,编辑时智能感知提醒,编译时发现  错误,这都是在一个大型项目中所需要的。虽然现在也有了调试 EntitySQL 的工具,但其与强类型的 LIN  Q  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)
  • 30. /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 文件定义并集成到  数据访问层。
  • 31. 在以往要在一个项目中动态创建实体,我所知的方法是把要添加的实体放入一个程序集,然后通过反射  加载程序集。现在可以通过动态更改 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(EntityType  entity)  的方法。我们只需要新建一个实体对象并调用这个方法添加实体即可。注意这个函数内部调用  entities.AddObject("EntitySetName",  entity);  最后调用 entities.SaveChanges()方法将修改保存回数据库,这是所有三种更新操作所需的。更新与删除  操作都需要先使用 ObjectService 定位操作的实体对象,更新操作直接使用赋值运算符,删除操作则调用  entites.DeleteObject(object  o);  方法。之后调用 entities.SaveChanges()方法保存,这个过程简单,不再赘述。  含有 Association 的 EDM 的使用  当前版本的 Entity  Framework 不支持自动延迟加载,  所有当前未使用的关系中的相关实体默认按不加载  处理,当我们需要通过关系获取一个实体对象时,我们可以采用两种方法: · 显示加载  实体框架针对  EntityReference  类的每个实例提供一个  Load  方法。此方法可用于显式加载与另一
  • 32. 实体相关的一个集合。我们只需在访问关系中实体之前调用其 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);  }  } · 预先加载  先看代码示例  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。
  • 33. 两种加载关系实体的方式的选择根据:如果针对关系数据你只需做一到两次查询,则使用显示加载更高效,  如果要持续访问关系实体中数据,则使用预先加载。  关系下的添加,更新与删除与上述操作基本相同,唯一需要注意的是删除操作不支持级联删除,需要手工  遍历所有的相关项并将其一一删除。注意这里删除操作不能使用 foreach 来遍历需要删除的关系实体。取  而代之的有两种方法: · while 法  while  (result.Order_Details.Count  >  0)  {  //  删除操作…  } · 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 控件也是很简单的。这源于使用 ObjectCo  ntext 操作返回的 IQueryable<T>对象或是使用 EntityClient 查询返回的 ObjectQuery 对象都实现了 IEnum  erable 接口。这样很容易将这些数据绑定到数据显示控件。更新操作可以按上文所述在相应的时间处理函  数中写更新 EDM 的程序即可。  Entity  Framework 的链接字符串  默认情况下(Visual  Studio 对 Entity  Framework 数据项目的默认设置),  EDM 这个 XML 文件被作为资源  在编译时嵌入到程序集中。这种情况下当更改 EDM 后需要重新编译这个程序集才能使更改生效。通过更  改项目属性也可以让 EDM 作为三个独立的 XML 文件存在于项目中。为了让应用程序可以找到 EDM(无
  • 34. 论其以什么方式存储)需要一个链接字符串来指示 EDM 所在的位置。实体模型设计器生成的链接字符串  如下所示:  <add name="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,其可以自动由配置文件检索这  个连接字符串  本文来源:  http://www.cnblogs.com/lsxqw2004/archive/2009/05/31/1495240.html#_Toc228672774