Entity Framework 学习

Entity Framework 学习初级篇1--EF基本概况... 2html

Entity Framework 学习初级篇2--ObjectContext、ObjectQuery、ObjectStateEntry、ObjectStateManager类的介绍... 7sql

Entity Framework 学习初级篇3-- LINQ TOEntities. 10数据库

Entity Framework 学习初级篇4--EntitySQL. 17编程

Entity Framework 学习初级篇5--ObjectQuery查询及方法... 23c#

Entity Framework 学习初级篇6--EntityClient. 31缓存

Entity Framework 学习初级篇7--基本操做:增长、更新、删除、事务... 37服务器

Entity Framework 学习中级篇1—EF支持复杂类型的实现... 41闭包

Entity Framework 学习中级篇2—存储过程(上). 47架构

Entity Framework 学习中级篇3—存储过程(中). 54并发

Entity Framework 学习中级篇4—存储过程(下). 61

Entity Framework 学习中级篇5—使EF支持Oracle9i67

Entity Framework 学习高级篇1—改善EF代码的方法(上)... 75

Entity Framework 学习高级篇2—改善EF代码的方法(下)... 81

Entity Framework 学习结束语... 84

 

 

 

Entity Framework 学习初级篇1--EF基本概况

最近在学习研究微软的EF,经过这时间的学习研究,感受这个EF目前来讲还不是很完善,半成品。不过,听说在.Net4.0中,微软将推荐使用此框架,并会有所改善。并且,如今基本上全部数据库均提供了对EF的支持。所以,为之后作技术准备能够学习研究如下。可是,我我的以为就目前来讲,在实际项目慎用此框架。

下面简单的介绍如下这个EF。

在.Net Framework SP1微软包含一个实体框架(Entity Framework),此框架能够理解成微软的一个ORM产品。用于支持开发人员经过对概念性应用程序模型编程(而不是直接对关系存储架构编程)来建立数据访问应用程序。目标是下降面向数据的应用程序所需的代码量并减轻维护工做。Entity Framework 应用程序有如下优势:

·                应用程序能够经过更加以应用程序为中心的概念性模型(包括具备继承性、复杂成员和关系的类型)来工做。

·                应用程序再也不对特定的数据引擎或存储架构具备硬编码依赖性。

·                能够在不更改应用程序代码的状况下更改概念性模型与特定于存储的架构之间的映射。

·                开发人员可使用可映射到各类存储架构(可能在不一样的数据库管理系统中实现)的一致的应用程序对象模型。

·                多个概念性模型能够映射到同一个存储架构。

·                语言集成查询支持可为查询提供针对概念性模型的编译时语法验证。

实体框架Entity Framework 是 ADO.NET 中的一组支持开发面向数据的软件应用程序的技术。在EF中的实体数据模型(EDM)由如下三种模型和具备相应文件扩展名的映射文件进行定义。

·                概念架构定义语言文件 (.csdl) -- 定义概念模型。

·                存储架构定义语言文件 (.ssdl) -- 定义存储模型(又称逻辑模型)。

·                映射规范语言文件 (.msl) -- 定义存储模型与概念模型之间的映射。

实体框架 使用这些基于 XML 的模型和映射文件将对概念模型中的实体和关系的建立、读取、更新和删除操做转换为数据源中的等效操做。EDM 甚至支持将概念模型中的实体映射到数据源中的存储过程。它提供如下方式用于查询EDM 并返回对象:

·                LINQ to Entities-- 提供语言集成查询 (LINQ) 支持用于查询在概念模型中定义的实体类型。

·                Entity SQL -- 与存储无关的 SQL 方言,直接使用概念模型中的实体并支持诸如继承和关系等 EDM 功能。

·                查询生成器方法 --可使用 LINQ 风格的查询方法构造 Entity SQL 查询。

下图演示用于访问数据的实体框架体系结构:

 

 

 

 

下面,来学习EF的基本使用方法。软件环境::

·                Visual Studio 2008 +SP1

·                SQL Server2005/2008

首先,创建一个名为“EFProject”的解决方案,而后添加一个名为“EFModel”的类库项目。以下图所示。

 

 

接着,在EFModel项目中,添加“ADO.NETEntity Data Model”项目,以下图所示:

 

 

名称取为“NorthWindEF.edmx”,而后点击“添加”。而后,在后面的步骤中,数据库选择“NorthWind”后,在选择影射对象是,把表、试图、存储过程所有都选上,其余的均保存默认的便可。最终生成的结果以下图所示。

 

 

 

好了,数据模型生成完毕。

最后,谈谈我认为的一些缺点:

·                Edmx包含了全部对象的csdl,ssdl,msl文件,过于庞大,若是要手动修改这个文件,一不当心,眼睛看花了,就改错了。(和数据集同样的毛病)。

·                目前EF支持表、试图、存储过程,其余的对象不支持,并且对使用存储过程有不少限制(目前有EFExtension提供了更多对象的支持)。

·                除了MSSQL Server可直接提供这种可视化的设计界面外,其余的数据库目前尚未提供可视化设计界面(但能够本身来实现,后面介绍)。

·                性能问题。(网上看到有说比ADO.Net慢,又有人说比ADO.net快的,具体状况我还没测试过, 但我以为像这个些类型的框架,性能确定是比上原生态的ADO.net慢)

好了,接下来,学习如下简单的各类操做。

 

Entity Framework 学习初级篇2--ObjectContextObjectQueryObjectStateEntryObjectStateManager类的介绍

本节,简单的介绍EF中的ObjectContext、ObjectQuery、ObjectStateEntryObjectStateManager这个几个比较重要的类,它们都位于System.Data.Entity.dll下的System.Data.Objects命名空间下。在后续的章节中,咱们常常会用到它们的某些方法,以便完成咱们的某些操做或目的。本节,简单的说明一下之后咱们可能会用到的各个类的方法,以方便咱们后续的学习。

ObjectContext封装 .NET Framework 和数据库之间的链接。此类用做“建立”、“读取”、“更新”和“删除”操做的网关。

ObjectContext 类为主类,用于与做为对象(这些对象为 EDM 中定义的实体类型的实例)的数据进行交互。

ObjectContext 类的实例封装如下内容:

l          到数据库的链接,以 EntityConnection 对象的形式封装。

l          描述该模型的元数据,以 MetadataWorkspace 对象的形式封装。

l          用于管理缓存中持久保存的对象的 ObjectStateManager对象。

ObjectContext类的成员方法以说明以下所示:

l          AcceptAllChanges()

接受全部对该实体对象的更改

l          AddObject(string,object)

将实体对象添加到制定的实体容器中

l          ApplyPropertyChanges(string,object)

将以指派的实体对象属性的更改应用到容器中对应的原对象。

l          Attach(System.Data.Objects.DataClasses.IEntityWithKeyentity)

将带主键的实体对象附加到默认的容器中

l          Attach(string,object)

将实体对象附加到指定的实体容器中

l          CreateEntityKey(string,object)

给指定的实体对象建立实体主键或若是已存在实体主键,则直接返回该实体的主键

l          CreateQuery<T>(string,paramsObjectParameter[])

从给定的查询字符串建立ObjectQuery对象。

l          DeleteObject(object)

删除指定的实体对象

l          Detach(object)

移除指定的实体对象

l          ExecuteFunction<TElement>(string,paramsObjectParameter[])

对默认容器执行给定的函数。

l          GetObjectByKey(System.Data.EntityKeykey)

经过主键KEY从 ObjectStateManager中检索对象(若是存在);不然从存储区中检索。

l          Refresh(System.Data.Objects.RefreshMode refreshMode,object entity)

按指定持久更新模式,使用指定实体的存储区数据更新ObjectStateManager。。

l          Refresh(System.Data.Objects.RefreshModerefreshMode, System.Collections.IEnumerable collection)

按指定持久处理模式,使用指定实体集的存储区数据更新ObjectStateManager

l          SaveChanges(bool)

将全部更新持久保存到存储区中。参数是客户端事务支持所需的参数。参数为true则在更新后自动将更改应用到ObjectStateManager中的实体。若是为false,则在更新后还须要调用AcceptAllChanges()以便更新ObjectStateManager中的实体。

l          SaveChanges()

将全部更新持久保存到存储区中

l          TryGetObjectByKey(System.Data.EntityKey,outobject)

尝试从指定实体主键返回该实体

以上各个方法的具体用法,将在后面介绍。

接着,再看看有用的类ObjectQuery。

ObjectQuery有个有用的方法ToTraceString(),这个方法用于追踪所执行的SQL语句,经过此方法咱们能够获取所执行的SQL语句,以便咱们查看、分析具体执行的SQL语句。(相似Nhibernate配置文件中的showsql节)

再了解一下ObjectStateEntry

ObjectStateEntry维护实体实例或关系实例的状态(已添加、已删除、已分离、已修改或未更改)、键值和原始值。还管理已修改属性的列表。其包含一下方法:

l          AcceptChanges

接受当前值做为原始值,并将实体标记为 Unchanged()。

l           Delete

将实体标记为 Deleted()。若是实体处于 Added()()() 状态,它将为 Detached()。

l          GetModifiedProperties

返回标记为 Modified()的属性名称。

l           SetModified

将状态设置为 Modified()。

l           SetModifiedProperty

将指定的属性标记为 Modified()。

接着,再看看ObjectStateManager

ObjectStateManager用于维护对象映射、对象状态/标识管理以及实体实例或关系实例的持久性。

l          GetObjectStateEntries

获取给定EntityState的ObjectStateEntry集合。

l          GetObjectStateEntry

获取给定的 EntityKey 对应的 ObjectStateEntry

如今,几个重要的类简单介绍完毕。后面,咱们将具体学习它们的使用。

 

Entity Framework 学习初级篇3-- LINQ TO Entities

 

LINQ 技术(即 LINQ to Entities)使开发人员可以经过使用 LINQ 表达式和 LINQ 标准查询运算符,直接从开发环境中针对 实体框架对象上下文建立灵活的强类型查询。LINQ to Entities 查询使用对象服务基础结构。ObjectContext 类是做为 CLR 对象与 实体数据模型 进行交互的主要类。开发人员经过 ObjectContext 构造泛型 ObjectQuery 实例。ObjectQuery 泛型类表示一个查询,此查询返回一个由类型化实体组成的实例或集合。返回的实体对象可供更新并位于对象上下文中。如下是建立和执行  LINQ to Entities 查询的过程:

1.     从 ObjectContext 构造 ObjectQuery 实例。

2.     经过使用 ObjectQuery 实例在 C# 或 Visual Basic 中编写 LINQ to Entities 查询。

3.     将 LINQ 标准查询运算符和表达式将转换为命令目录树。

4.     对数据源执行命令目录树表示形式的查询。执行过程当中在数据源上引起的任何异常都将直接向上传递到客户端。

5.     将查询结果返回到客户端。

1、Linq To Entities简单查询

下面将介绍简单的Linq To Entities查询,相关的查询语法可使用基于表达式或基于方法的语法。本节使用的TestDriver.Net配合Nunit2.4进行测试。

1,  投影

代码以下:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Data.Objects;

usingNUnit.Framework;

namespaceNorthWindModel

{

   [TestFixture]

   public classTestEFModel

   {

        [Test]

        public void Select()

        {

            using(var edm = new NorthwindEntities())

            {

                //基于表达式的查询语法

                ObjectQuery<Customers> customers = edm.Customers;

                IQueryable<Customers> cust1 = fromc in customers

                                              select c;

                Assert.Greater(cust1.Count(),0);

               //使用ObjectQuery类的ToTraceString()方法显示查询SQL语句

                Console.WriteLine(customers.ToTraceString());

 

 

            }

        }

   }

}

输出:

SELECT

[Extent1].[CustomerID] AS[CustomerID],

[Extent1].[CompanyName] AS[CompanyName],

[Extent1].[ContactName] AS[ContactName],

[Extent1].[ContactTitle] AS[ContactTitle],

[Extent1].[Address] AS [Address],

[Extent1].[City] AS [City],

[Extent1].[Region] AS [Region],

[Extent1].[PostalCode] AS[PostalCode],

[Extent1].[Country] AS [Country],

[Extent1].[Phone] AS [Phone],

[Extent1].[Fax] AS [Fax]

FROM [dbo].[Customers] AS [Extent1]

 

1 passed, 0 failed, 0 skipped, took 11.00 seconds (NUnit2.4).

在上面的输出内容中,能够看到使用了ToTraceString()方法来输出具体的SQL语句。同时Nunit也输出相关的测试状况,请注意查询所花费的时间,以便咱们进行查询速度的分析比较。

2,  条件限制

using(var edm = new NorthwindEntities())

{

   //基于表达式的查询语法

   ObjectQuery<Customers> customers = edm.Customers;

   IQueryable<Customers> cust1 = from c in customers

                                  where c.CustomerID == "ALFKI"

                                  select c;

  

   Assert.AreEqual(cust1.Count(), 1);

   foreach (varc in cust1)

        Console.WriteLine("CustomerID={0}", c.CustomerID);

              

   //基于方法的查询语法

   var cust2 = edm.Customers.Where(c =>c.CustomerID == "ALFKI");

   Assert.AreEqual(cust2.Count(), 1);

   foreach (varc in cust2)

          Console.WriteLine("CustomerID={0}", c.CustomerID);

 

}

3,  排序和分页

在使用Skip和Take方法实现分页时,必须先对数据进行排序,不然将会抛异常。

using(var edm = new NorthwindEntities())

 {

//基于表达式的查询语法

         ObjectQuery<Customers> customers = edm.Customers;

         IQueryable<Customers> cust10 = (fromc in customers

                                         orderby c.CustomerID

                                         select c).Skip(0).Take(10);

 

          Assert.AreEqual(cust10.Count(),10);

          foreach(var c incust10)

              Console.WriteLine("CustomerID={0}", c.CustomerID);

   

//基于方法的查询语法

    var cust =edm.Customers.OrderBy(c => c.CustomerID).Skip(0).Take(10);

    Assert.AreEqual(cust.Count(),10);

    foreach (var c in cust)

        Console.WriteLine("CustomerID={0}", c.CustomerID);

 }

4,  聚合

可以使用的聚合运算符有Average、Count、Max、Min 和 Sum。

using (varedm = new NorthwindEntities())

   {

       varmaxuprice = edm.Products.Max(p => p.UnitPrice);

       Console.WriteLine(maxuprice.Value);

 }

5,  链接

能够的链接有Join 和 GroupJoin 方法。GroupJoin组联接等效于左外部联接,它返回第一个(左侧)数据源的每一个元素(即便其余数据源中没有关联元素)。

using(var edm = new NorthwindEntities())

    {

       var query = from d in edm.Order_Details

                   joinorder in edm.Orders

                   ond.OrderID equals order.OrderID

                   selectnew

                    {

                        OrderId =order.OrderID,

                        ProductId = d.ProductID,

                        UnitPrice = d.UnitPrice

                     };

        foreach(var q inquery)

         Console.WriteLine("{0},{1},{2}",q.OrderId,q.ProductId,q.UnitPrice);

}

其余一些方法等就很少说了,和Linq to SQL基本上是同样的。

2、LINQ to Entities 查询注意事项

l          排序信息丢失

若是在排序操做以后执行了任何其余操做,则不能保证这些附加操做中会保留排序结果。这些操做包括 Select 和 Where 等。另外,采用表达式做为输入参数的 FirstFirstOrDefault方法不保留顺序。

以下代码:并不能达到反序排序的效果

using (varedm = new NorthwindEntities())

{

     IQueryable<Customers>cc = edm.Customers.OrderByDescending(c => c.CustomerID).Where(c =>c.Region != null).Select(c => c);

     foreach (var c in cc)

          Console.WriteLine(c.CustomerID);

}

l          不支持无符号整数

因为 实体框架不支持无符号整数,所以不支持在 LINQ to Entities 查询中指定无符号整数类型。若是指定无符号整数,则在查询表达式转换过程当中会引起NotSupportedException异常,并显示没法建立类型为“结束类型”的常量值。此上下文仅支持基元类型(“例如  Int3二、String 和 Guid”)。

以下将会报异常的代码:

using(var edm = new NorthwindEntities())

 {

      uint id = UInt32.Parse("123");

      IQueryable<string>produt = from p inedm.Products

                                  where p.UnitPrice == id

                                  select p.ProductName;

      foreach (string name in produt)

            Console.WriteLine(name);

}

上面的代码中,因为id是uint而不是Int32,String,Guid的标量类型,因此在执行到where p.UnitPrice ==id这个地方时,会报异常。

l          不支持引用非标量闭包

不支持在查询中引用非标量闭包(如实体)。在执行这类查询时,会引起 NotSupportedException 异常,并显示消息“没法建立类型为“结束类型”的常量值。此上下文中仅支持基元类型(‘如 Int3二、String 和 Guid’)

以下将会报异常的代码:

using (var edm = new NorthwindEntities())

 {

        Customers customer = edm.Customers.FirstOrDefault();

        IQueryable<string>cc = from c inedm.Customers

                                where c == customer

                                select c.ContactName;

         foreach (string name in cc)

               Console.WriteLine(name);

}

上面的代码中,因为customer是引用类型而不是Int32,String,Guid的标量类型,因此在执行到where c==customer这个地方时,会报异常。

好,本节介绍完毕。后面将继续学习EF.

 

Entity Framework 学习初级篇4--Entity SQL

Entity SQL 是 ADO.NET 实体框架 提供的 SQL 类语言,用于支持 实体数据模型 (EDM)。Entity SQL 可用于对象查询和使用 EntityClient 提供程序执行的查询。

l          关键字

Value关键字

 ESQL 提供了 SELECT VALUE 子句以跳过隐式行构造。SELECT VALUE 子句中只能指定一项。在使用这样的子句时,将不会对 SELECT 子句中的项构造行包装器,而且可生成所要形状的集合,例如:SELECTVALUE it FROM NorthwindEntities.Customers as it

it关键字

it 出如今 ESQL 中, 查询对象的别名默认值"it" 改为其余字符串,例如:

"SELECT VALUE it FROM NorthwindEntities.Customersas it "

l          注释:

Entity SQL 查询能够包含注释。注释行以两个短划线 (--) 开头。

"SELECT VALUE it FROMNorthwindEntities.Customers as it  --this a comment "

l          Select查询

例如:

SELECT VALUE it FROMNorthwindEntities.Customers as it

l          参数

参数是在esql以外定义的变量,每一个参数都有名称和类型,参数名称在查询表达式中定义,并以@符号做为前缀。例如:

Select VALUE c fromNorthwindEntities.Customers as c where c.CustomerID=@customerID

l          聚合

Enity SQL不支持 * ,因此esql不支持count(*),而是使用count(0),例如:

Select count(0) fromNorthwindEntities.Customers

l          分页SKIP/LIMIT

能够经过在 ORDER BY 子句中使用 SKIP 和 LIMIT 子子句执行物理分页。若要以肯定的方式执行物理分页,应使用 SKIP 和 LIMIT。若是您只是但愿以非肯定的方式限制结果中的行数,则应使用 TOP。TOP 和 SKIP/LIMIT 是互斥的

使用SKIP/LIMIT分页,esql代码以下:

Select value c fromNorthwindEntities.Customers as c order by c.CustomerID skip 0 limit 10

l          TOP

SELECT 子句能够在可选的 ALL/DISTINCT 修饰符以后具备可选的 TOP 子子句。TOP 子子句指定查询结果中将只返回第一组行。esql代码以下:

Select top(10) c.CustomerID fromNorthwindEntities.Customers as c order by c.CustomerID

l          NULL处理

Null 文本与 Entity SQL 类型系统中的任何类型都兼容,可使用cast进行类型转换,例如:

select cast(c.region as string) fromNorthwindEntities.Customers as c order by c.CustomerID limit 10

其中, Nvarchar等能够成string,数字类型能够转成int32,其余的类型转换相似。若是没法完成转换,则将报异常。还有能够处理的方法有treat。

l          标识符

Entity SQL 提供两种标识符:简单标识符和带引号的标识符

简单标识符:Entity SQL 中的简单标识符是字母数字和下划线字符的序列。标识符的第一个字符必须是字母字符(a-z 或 A-Z)。

带引号的标识符:带引号的标识符是括在方括号 ([]) 中的任何字符序列。带中文的部分,请使用方括号包括起来,不然会报以下异常信息:“简单标识符“中文”只能包含基本拉丁字符。若要使用UNICODE 字符,请使用转义标识符”

正确的代码以下:

Select c.CustomerID as [中文字符] from NorthwindEntities.Customers as c order by c.CustomerIDskip 0 limit 10

l          ROW

Esql可以使用row来构建匿名的结构类型的纪录。例如:

SELECT VALUE row(p.ProductID asProductID,p.ProductName as ProductName) FROM NorthwindEntities.Products as porder by p.ProductID LIMIT 10

l          Key

提取引用或实体表达式的键。以下esql语句,直接返回Customer表的主键:

string esql = "SELECT value key(c)FROM NorthwindEntities.Customers as c order by c.CustomerID LIMIT 10"

l          CreateRef/ref/deref

CreateRef建立对实体集中的实体的引用。

ref返回对实体实例的引用,以后就能够看成实体来访问其属性,esql语句以下:

SELECT ref(c).CustomerID FROMNorthwindEntities.Customers as c order by c.CustomerID LIMIT 10

deref运算符取消引用一个引用值,并生成该取消引用的结果。

l          CASE语句:

 string esql = "using SqlServer;select case whenlen(trim(c.CustomerID))==0 then true else false end  from NorthwindEntities.Customers as c orderby c.CustomerID limit 10";

l          运算符

Esql支持的运算符有:加+、减-、乘*、除/、取模%、-负号。Esql语句以下:

select 100/2 as OP fromNorthwindEntities.Customers as c order by c.CustomerID limit 10

l          比较运算符

Esql支持的比较运算符有:=,>,>=,IS [NOT]NULL,<,[NOT] BETWEEN,!=,<>,[NOT] LIKE。Esql语句以下:

select value p fromNorthwindEntities.Products as p where p.UnitPrice > 20 order by p.ProductIDlimit 10

l          逻辑运算符

Esql支持的逻辑运算符有:and(&&),not(!),or(||)。Esql语句以下:

select value p fromNorthwindEntities.Products as p where p.UnitPrice > 20 and p.UnitPrice<100order by p.ProductID limit 10

select value p fromNorthwindEntities.Products as p where p.UnitPrice > 20 &&p.UnitPrice<100 order by p.ProductID limit 10

l          字符串链接运算符。

加号 (+) 是 Entity SQL 中可将字符串串联起来的惟一运算符。Esql语句以下:

select c.CustomerID + c.ContactName fromNorthwindEntities.Customers as c  orderby c.CustomerID limit 10

l          嵌套查询

在 Entity SQL 中,嵌套查询必须括在括号中,将不保留嵌套查询的顺序

select c1.CustomerID from( select valuec from NorthwindEntities.Customers as c order by c.CustomerID limit 10) as c1

l          日期时间函数

Esql提供的日期时间函数有:CurrentDateTime()获取当前服务器的日期时间,还有month,day,year,second,Minute ,Hour等。例如:

select CurrentDateTime()  from NorthwindEntities.Customers as c  order by c.CustomerID limit 10

l          字符串函数

Esql提供的字符串函数有:Concat,IndexOf,Left,Length,Ltrim,Replace,Reverse,Rtrim,SubString,Trim,ToLower,ToUpper.例如:

select Reverse(p.ProductName) asProductName from NorthwindEntities.Products as p  order by p.ProductID limit 10

l          GUID

Esql提供newguid()函数,产生一个新的Guid。例如:

select newguid()  from NorthwindEntities.Customers as c  order by c.CustomerID limit 10

l          数学函数:

Abs,Ceiling,Floor,Round

l          统计函数:

Avg,BigCount,Count,Max,Min,StDev,Sum

l          位计算函数

若是提供 Null 输入,则这些函数返回 Null。这些函数的返回类型与参数类型相同。若是函数采用多个参数,则这些参数必须具备相同的类型。若要对不一样类型执行位运算,则须要显式强制转换为相同类型.

BitWiseAnd,BitWiseNot,BitWiseOr,BitWiseXor

l          命名空间

Entity SQL 引入命名空间以免全局标识符(如类型名称、实体集、函数等)出现名称冲突。Entity SQL 中的命名空间支持与 .NET Framework 中的命名空间支持相似。

Entity SQL 提供两种形式的 USING 子句:限定命名空间(其中,提供较短的别名以表示命名空间)和非限定命名空间,以下例所示:

USING System.Data;

USING tsql =System.Data;

例如:

string esql = "using System; select cast(p.UnitPrice asInt32)  from NorthwindEntities.Productsas p  order by p.ProductID limit 10";

string esql = "using System;using SqlServer; select(cast(p.UnitPrice as Int32)),SqlServer.ltrim(p.ProductName) as nameLen fromNorthwindEntities.Products as p  order byp.ProductID limit 10 ";

 

最后,简单说一下Esql与T-Sql的某些差别:

l          Entity SQL 中的全部列引用都必须用表别名限定.

l          Esql不支持Any,all限定运算符以及*运算

l          Entity SQL 当前未提供对 DML 语句(insert、update、delete)的支持。

l           Entity SQL 的当前版本未提供对 DDL 的支持。

 

Entity Framework 学习初级篇5--ObjectQuery查询及方法

 

ObjectQuery 类支持对 实体数据模型 (EDM) 执行 LINQ to Entities 和 Entity SQL 查询。ObjectQuery 还实现了一组查询生成器方法,这些方法可用于按顺序构造等效于 Entity SQL 的查询命令。下面是ObjectQuery 的查询生成器方法以及等效的 Entity SQL 语句:

Distinct,Except,GroupBy,Intersect,OfType,OrderBy,Select,SelectValue,Skip,Top,Union,UnionAll,Where

每一个查询生成器方法返回 ObjectQuery 的一个新实例。使用这些方法能够构造查询,而查询的结果集基于前面 ObjectQuery 实例序列的操做。下面来看具体的代码片段:

l          Execute方法:

using(var edm = new NorthwindEntities())

        {

                stringesql = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query = edm.CreateQuery<Customers>(esql);

                ObjectResult<Customers> results = query.Execute(MergeOption.NoTracking);

                Assert.AreEqual(results.Count(),10);

                foreach(Customers c inquery)

                    Console.WriteLine(c.CustomerID);

            }

其中须要说明的是: MergeOption这个枚举类型的参数项,MergeOption有四种值分别是:

l          AppendOnly: 只追加新实体,不修改之前获取的现有实体。这是默认行为。

l          OverwriteChanges: 将 ObjectStateEntry 中的当前值替换为存储区中的值。这将使用服务器上的数据重写在本地所作的更改。

l          PreserveChanges: 将替换原始值,而不修改当前值。这对于在发生开放式并发异常以后强制成功保存本地值很是有用。

l          NoTracking: 将不修改ObjectStateManager,不会获取与其余对象相关联的关系,能够改善性能。

l          GetResultType方法:返回查询结果的类型信息.例如:

using(var edm = new NorthwindEntities())

            {

                stringesql = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query = edm.CreateQuery<Customers>(esql);

                Console.WriteLine(query.GetResultType().ToString());

                //输出结果为:

                //NorthWindModel.Customers

            }

l          ToTraceString方法:获取当前执行的SQL语句。

l          Where

实例代码以下:

using(var edm = new NorthwindEntities())

     {

                stringesql = "select value c fromNorthwindEntities.Customers as c ";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql);

               //使用ObjectParameter的写法               

                query1 = query1.Where("it.CustomerId=@customerid");

                query1.Parameters.Add(new ObjectParameter("customerid", "ALFKI"));

               //也能够这样写

                //ObjectQuery<Customers>query2 = edm.Customers.Where("it.CustomerID='ALFKI'");

                foreach(var c inquery1)

                    Console.WriteLine(c.CustomerID);

                //显示查询执行的SQL语句

                Console.WriteLine(query1.ToTraceString());

              

            }

l          First/ FirstOrDefault

实例代码以下:

using(var edm = new NorthwindEntities())

     {

                stringesql = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query = edm.CreateQuery<Customers>(esql);

                Customersc1 = query.First();

                Customersc2 = query.FirstOrDefault();

                Console.WriteLine(c1.CustomerID);

                Assert.IsNotNull(c2);

                Console.WriteLine(c2.CustomerID);

      }

l          Distinct

实例代码以下:

using (varedm = new NorthwindEntities())

    {

                stringesql = "select value c.City fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<string> query = edm.CreateQuery<string>(esql);

                query = query.Distinct();

                foreach(string c inquery)

                {

                    Console.WriteLine("City {0}", c);

                }

     }

l          Except:返回两个查询的差集。实例代码以下:

using (varedm = new NorthwindEntities())

     {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                stringesql2 = "select value c fromNorthwindEntities.Customers as c where c.Country='UK' order by c.CustomerID limit10";

                ObjectQuery<Customers> query2 = edm.CreateQuery<Customers>(esql2);

                query1 = query1.Except(query2);

                foreach (Customers c inquery1)

                {

                    Console.WriteLine(c.Country);

                    //输出:UK

                }

        }

l          Intersect:返回两个查询的交集。实例代码以下:

using (varedm = new NorthwindEntities())

     {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                stringesql2 = "select value c from NorthwindEntities.Customersas c where c.Country='UK'order by c.CustomerID limit 10";

                ObjectQuery<Customers> query2 = edm.CreateQuery<Customers>(esql2);

                query1 =query1.Intersect(query2);

                foreach(Customers c inquery1)

                {

                    Console.WriteLine(c.Country);

                }

      }

l          Union/UnionAll:返回两个查询的合集,包括重复项。其中UnionAll必须是相同类型或者是能够相互转换的。

l          Include:可经过此方法查询出与相关的实体对象。实例代码以下:

using (varedm = new NorthwindEntities())

     {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c WHERE c.CustomerID ='HANAR'";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                query1 = query1.Include("Orders");

                foreach(Customers c inquery1)

                {

                    Console.WriteLine("{0},{1}", c.CustomerID,c.Orders.Count);

                    //输出:HANAR,14

                }

 

     }

l          OfType: 根据制定类筛选元素建立一个新的类型。此类型是要在实体模型中已定义过的。

l          OrderBy

实例代码以下:

using (varedm = new NorthwindEntities())

    {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                query1.OrderBy("it.country asc,it.city asc");

//也能够这样写               

//query1.OrderBy("it.countryasc");

                //query1.OrderBy("it.cityasc");

                foreach(Customers c inquery1)

                {

                    Console.WriteLine("{0},{1}", c.Country, c.City);

                }

      }

l          Select

实例代码以下:

using (varedm = new NorthwindEntities())

    {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                ObjectQuery<DbDataRecord> records = query1.Select("it.customerid,it.country");

                foreach(DbDataRecord c inrecords)

                {

                    Console.WriteLine("{0},{1}", c[0], c[1]);

                }

                Console.WriteLine(records.ToTraceString());

                //SQL输出:

                //SELECTTOP (10)

                //1AS [C1],

                //[Extent1].[CustomerID]AS [CustomerID],

                //[Extent1].[Country]AS [Country]

                //FROM[dbo].[Customers] AS [Extent1]

                //ORDERBY [Extent1].[CustomerID] ASC

      }

l          SelectValue

实例代码以下:

using (varedm = new NorthwindEntities())

    {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                ObjectQuery<string> records = query1.SelectValue<string>("it.customerid");

                foreach(string c inrecords)

                {

                    Console.WriteLine("{0}", c);

                }

                Console.WriteLine(records.ToTraceString());

                //SQL输出:

                //SELECTTOP (10)

                //[Extent1].[CustomerID]AS [CustomerID]

                //FROM[dbo].[Customers] AS [Extent1]

                //ORDERBY [Extent1].[CustomerID] ASC

       }

l          Skip/Top

实例代码以下:

using (varedm = new NorthwindEntities())

    {

                stringesql1 = "select value c fromNorthwindEntities.Customers as c order by c.CustomerID ";

                ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(esql1);

                query1 = query1.Skip("it.customerid asc", "10");

                query1 = query1.Top("10");

                foreach(Customers c inquery1)

                {

                    Console.WriteLine("{0}", c.CustomerID);

                }

                Console.WriteLine(query1.ToTraceString());

                //SQL输出:

                //SELECTTOP (10)

                //[Extent1].[CustomerID]AS [CustomerID]

                //FROM[dbo].[Customers] AS [Extent1]

                //ORDERBY [Extent1].[CustomerID] ASC

}

   本节,简单的介绍一下与ObjectQuery查询相关的语法,我我的以为查询写法比较多,须要在平常的编程中去发现,在这里就不一一复述了。下节,将介绍EntityClient相关的内容。

 

Entity Framework 学习初级篇6--EntityClient

 

System.Data.EntityClient 命名空间是 实体框架的 .NET Framework 数据提供程序。EntityClient 提供程序使用存储特定的 ADO.NET 数据提供程序类和映射元数据与实体数据模型进行交互。EntityClient 首先将对概念性实体执行的操做转换为对物理数据源执行的操做。而后再将物理数据源返回的结果集转换为概念性实体。

EntityClient下的类有如下几个:

l          EntityConnection

l          EntityCommand

l          EntityConnectionStringBuilder

l          EntityParameter

l          EntityDataReader 

l          EntityParameterCollection

l          EntityProviderFactory

l          EntityTransaction

从类的名字上看,咱们就知道它们的做用是什么了。在此,就再也不一一解释了。直接经过实例代码来学习它们。

l        EntityConnection:

实例代码1:

stringcon = "name = NorthwindEntities";

            using(EntityConnection econn = new EntityConnection(con))

            {

                stringesql = "Select VALUE c fromNorthwindEntities.Customers as c where c.CustomerID='ALFKI'";

                econn.Open();

                EntityCommandecmd = new EntityCommand(esql,econn);

                EntityDataReaderereader = ecmd.ExecuteReader(CommandBehavior.SequentialAccess);

                if(ereader.Read())

                {

                    Console.WriteLine(ereader["CustomerID"]);

                }

                Console.WriteLine(ecmd.ToTraceString());

            }

上述代码中,须要注意的是EntityConnection的构造方法。其中,链接字符串写法有多很,以下:

写法1:

string con ="name = NorthwindEntities" ;其中的”NorthwindEntities”是配置文件中的链接字符串名称

写法2:

string con =System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindEntities"].ConnectionString;其中的”NorthwindEntities”是配置文件中的链接字符串名称

写法3:

string con = @"metadata=res://*/NorthWind.csdl|res://*/NorthWind.ssdl|res://*/NorthWind.msl;provider=System.Data.SqlClient;providerconnection string='Data Source=.\SQLEXPRESS;InitialCatalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True'";其中的这些字符串是配置文件中的链接字符串的值

写法4:

NorthwindEntitiesedm = new NorthwindEntities();

string con =edm.Connection.ConnectionString;

上述写法中,基于写法简单、方便我比较推荐使用第1种或者第2种写法。

l        EntityCommand

它具备的方法有:ExecuteDbDataReader、 ExecuteNonQuery 、 ExecuteReader 、 ExecuteScalar等。

实例代码2:

stringcon = "name = NorthwindEntities";

            using(EntityConnection econn = new EntityConnection(con))

            {

                stringesql = "Select VALUE c fromNorthwindEntities.Customers as c where c.CustomerID='ALFKI'";

                econn.Open();

                EntityCommandecmd = econn.CreateCommand();

                ecmd.CommandText = esql;

                EntityDataReaderereader = ecmd.ExecuteReader(CommandBehavior.SequentialAccess);

                if(ereader.Read())

                {

                    Console.WriteLine(ereader["CustomerID"]);

                }

                Console.WriteLine(ecmd.ToTraceString());

            }

代码中,EntityCommand建立方式和实例代码1中的稍有不一样,相信你们都明白,就很少说了。

l        EntityConnectionStringBuilder

实例代码3:

           EntityConnectionStringBuilder esb = newEntityConnectionStringBuilder();

            esb.Provider = "System.Data.SqlClient";

            esb.Metadata = @"res://*/NorthWind.csdl|res://*/NorthWind.ssdl|res://*/NorthWind.msl";

            esb.ProviderConnectionString = @"Data Source=.\SQLEXPRESS;InitialCatalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True";

           EntityConnectioneconn = new EntityConnection(esb.ConnectionString)//建立链接

l        EntityParameter

代码实例4:

stringcon = "name = NorthwindEntities";

            using(EntityConnection econn = new EntityConnection(con))

            {

                stringesql = "Select value c fromNorthwindEntities.Customers as c order by c.CustomerID skip @start limit@end";

                econn.Open();

                EntityCommandecmd = new EntityCommand(esql,econn);

                EntityParameterp1 = new EntityParameter("start", DbType.Int32);

                p1.Value = 0;

                EntityParameterp2 = new EntityParameter("end", DbType.Int32);

                p2.Value = 10;

                ecmd.Parameters.Add(p1);

                ecmd.Parameters.Add(p2);

                 EntityDataReaderereader = ecmd.ExecuteReader(CommandBehavior.SequentialAccess);

                while(ereader.Read())

                {

                    Console.WriteLine(ereader["CustomerID"]);

                }

                Console.WriteLine(ecmd.ToTraceString());

            }

其中,参数是以@符号前缀的,EntityParameter实体参数类,除了能够直接构造出实例来。为实体命令对象添加参数,咱们还能够直接调用Parameters.AddWithValue方法。以下代码:

     ecmd.Parameters.AddWithValue("start",0);

    ecmd.Parameters.AddWithValue("end", 10);

    我比较喜欢用上面的代码,简单、方便。

l        EntityDataReader

stringcon = "name = NorthwindEntities";

            using(EntityConnection econn = new EntityConnection(con))

            {

                stringesql = "Select value c fromNorthwindEntities.Customers as c order by c.CustomerID limit 10 ";

                econn.Open();

                EntityCommandecmd = new EntityCommand(esql,econn);

                EntityDataReaderereader = ecmd.ExecuteReader(CommandBehavior.SequentialAccess);

                while(ereader.Read())

                {

                    Console.WriteLine("{0},{1},{2},{3},{4}", ereader[0],ereader[1], ereader[2], ereader[3], ereader[4]);              

                }

                Console.WriteLine(ecmd.ToTraceString());

            }

须要注意的是:CommandBehavior.SequentialAccess;这个地方。不一样的枚举项,对查询会有不一样影响。枚举以下:

l          Default 此查询可能返回多个结果集。在功能上等效于调用 ExecuteReader()。 

l          SingleResult 查询返回一个结果集。 

l          SchemaOnly 查询仅返回列信息。

l          KeyInfo 此查询返回列和主键信息。 

l          SingleRow 查询应返回一行。

l          SequentialAccess 提供一种方法,以便 DataReader处理包含带有大二进制值的列的行。

l          CloseConnection 在执行该命令时,若是关闭关联的DataReader 对象,则关联的 Connection 对象也将关闭。

须要说明的是,若是使用SequentialAccess则需按顺序访问列,不然将抛异常。以下代码,将会抛异常:

while (ereader.Read())

    {

          //异常信息:从列序列号“1”开始读取的尝试无效。经过CommandBehavior.SequentialAccess,只能从列序列号“5”或更大值处开始读取

          Console.WriteLine("{0},{1},{2},{3},{4}", ereader[4],ereader[1], ereader[2], ereader[3], ereader[0]);    

}

l        EntityTransaction

事务类。目前因为ESQL仅提供查询的命令,没有提供对Insert、Update、Delete等的支持。因此,我以为目前这个类基本没有用,(不可能我作查询还使用事务吧!)。

从上述简单的介绍,咱们能够看到,EntityClient和SqlClient下的类基本上是一致的。因此很容易掌握。其余就很少说了。

 

Entity Framework 学习初级篇7--基本操做:增长、更新、删除、事务

 

本节,直接写经过代码来学习。这些基本操做都比较简单,与这些基本操做相关的内容在以前的1至6节基本介绍完毕。

l          增长:

方法1:使用AddToXXX(xxx)方法:实例代码以下:

           using (var edm = new NorthwindEntities())

            {

                Customersc = new Customers{ CustomerID = "c#", City = "成都市",Address = "中国四川省", CompanyName= "cnblogs", Country = "中国",Fax = "10086", Phone = "1008611", PostalCode = "610000", Region = "天府广场",ContactName = "风车车.Net" };

                edm.AddToCustomers(c);

                intresult = edm.SaveChanges();

                Assert.AreEqual(result,1);

                Customersaddc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c#");

                Console.WriteLine("CustomerId={0},City={1}",addc.CustomerID, addc.City);

            }

方法2:使用ObjectContext的AddObject(string entitySetName, object entity)方法。实例代码以下:

using (varedm = new NorthwindEntities())

            {

                    Customersc = new Customers{ CustomerID = "c2", City = "成都市2",Address = "中国四川省2", CompanyName= "cnblogs", Country = "中国",Fax = "10086", Phone = "1008611", PostalCode = "610000", Region = "天府广场",ContactName = "风车车.Net" };

                    edm.AddObject("Customers", c);

                    intresult = edm.SaveChanges();

                    Assert.AreEqual(result,1);

                    Customersaddc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c2");

                    Console.WriteLine("CustomerId={0},City={1}",addc.CustomerID, addc.City);

             }

其中,在代码中,须要注意的是:AddObject方法中参数“entitySetName ”就是指对应实体名称,应该是:“Customers”,而不是“NorthwindEntities.Customers”;

l          更新:

using (varedm = new NorthwindEntities())

            {

                    Customersaddc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c2");

                    addc.City = "CD";

                    addc.ContactName = "cnblogs";

                    addc.Country = "CN";

                    intresult = edm.SaveChanges();

                    Assert.AreEqual(result,1);

                    Customersupdatec = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c2");

                    Console.WriteLine("CustomerId={0},City={1}",updatec.CustomerID, updatec.City);

              }

其中,须要注意的是:不能去更新主键,不然会报“System.InvalidOperationException : 属性“xxx”是对象的键信息的一部分,不能修改。”

l          删除:

实例代码以下:

using (varedm = new NorthwindEntities())

        {

                    Customersdeletec = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c2");

                    edm.DeleteObject(deletec);

                    intresult = edm.SaveChanges();

                    Assert.AreEqual(result,1);

                    Customersc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c2");

                    Assert.AreEqual(c,null);

                

         }

l          事务:

实例代码以下:

NorthwindEntitiesedm = null;

            System.Data.Common.DbTransaction tran = null;

            try

            {

                edm = newNorthwindEntities();

                edm.Connection.Open();

                tran = edm.Connection.BeginTransaction();

                Customerscst = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "c#");

                cst.Country = "CN";

                cst.City = "CD";

                edm.SaveChanges();

                tran.Commit();

            }

            catch(Exception ex)

            {

                if(tran != null)

                    tran.Rollback();

                throwex;

            }

            finally

            {

                if(edm != null && edm.Connection.State !=System.Data.ConnectionState.Closed)

                    edm.Connection.Close();

            }

至此,初级篇基本介绍完毕。后面,打算写点,中级篇的东西。

 

Entity Framework 学习中级篇1—EF支持复杂类型的实现

 

本节,将介绍如何手动构造复杂类型(ComplexType)以及复杂类型的简单操做。

一般,复杂类型是指那些由几个简单的类型组合而成的类型。好比:一张Customer表,其中有FristName和LastName字段,那么对应的Customer实体类将会有FristName和LastName这两个属性。当咱们想把FirstName和LastName合成一个名为CustomerName属性时,此时,若是要在EF中实现这个目的,那么咱们就须要用到复杂类型。

目前,因为EF不能显示支持复杂类型,因此咱们没法在VS里的可视化设计器里面来设计咱们须要的复杂类型。因此,咱们须要手动修改实体模型,以便使其支持复杂类型的属性。修改的主要步骤有如下几步:

l         产生实体模型

l         修改CSDL文件

l         修改msl文件

l         从新生成模型实体类

在后续的介绍,我使用数据库使用的是NorthWind,并针对Customer表对应的实体类来增长复杂属性Address,其中复杂属性Address由Address,City,Region,Country和PostalCode这个几个组合而成。

下面,介绍具体的操做步骤:

第一步:产生实体模型

实体模型的产生咱们能够直接经过在VS可视化设计器来产生(若是不会,请参考《Entity Framework 学习初级篇1--EF基本概况》)。或者使用EdmGen工具来产生(EdmGen工具位于:系统盘符:\WINDOWS\Microsoft.NET\Framework\v3.5下面)。具体步骤就不复述了。

我产生的实体模型文件是:NorthwindEnites.edmx

第二步:修改csdl文件

产生了实体模型后,咱们使用记事本或其余文本编辑工具打开实体模型,(小技巧:能够把实体模型后缀.edmx改成.xml,而后把实体模型文件直接拖到VS里面进行修改,这样修改起来比较方便,待修改完毕后,将后缀改回来便可。)

接着,开始手动修改csdl文件,找到模型文件中关于csdl定义的部分,而后找到实体类型名为Customers的定义节,删除原来的Address,City,Region,Country,PostalCode属性定义,而后添加一个名为Address的属性,以下代码所示:

       <EntityTypeName="Customers">

          <Key>

            <PropertyRefName="CustomerID" />

          </Key>

          <PropertyName="CustomerID"Type="String"Nullable="false"MaxLength="5"Unicode="true"FixedLength="true" />

          <PropertyName="CompanyName"Type="String"Nullable="false"MaxLength="40"Unicode="true"FixedLength="false" />

          <PropertyName="ContactName"Type="String"MaxLength="30"Unicode="true"FixedLength="false" />

          <PropertyName="ContactTitle"Type="String"MaxLength="30"Unicode="true"FixedLength="false" />

          <PropertyName="Address"Type="NorthwindModel.CommonAddress"Nullable="false"></Property>

          <PropertyName="Phone"Type="String"MaxLength="24"Unicode="true"FixedLength="false" />

          <PropertyName="Fax"Type="String"MaxLength="24"Unicode="true"FixedLength="false" />

          <NavigationPropertyName="Orders"Relationship="NorthwindModel.FK_Orders_Customers"FromRole="Customers"ToRole="Orders" />

          <NavigationPropertyName="CustomerDemographics"Relationship="NorthwindModel.CustomerCustomerDemo"FromRole="Customers"ToRole="CustomerDemographics" />

        </EntityType>

接着,须要添加一个名为CommonAddress复杂类型的定义,具体以下代码:

<ComplexTypeName="CommonAddress">

          <PropertyName="Address"Type="String"MaxLength="60"Unicode="true"FixedLength="false" />

          <PropertyName="City"Type="String"MaxLength="15"Unicode="true"FixedLength="false" />

          <PropertyName="Region"Type="String"MaxLength="15"Unicode="true"FixedLength="false" />

          <PropertyName="PostalCode"Type="String"MaxLength="10"Unicode="true"FixedLength="false" />

          <PropertyName="Country"Type="String"MaxLength="15"Unicode="true"FixedLength="false" />

        </ComplexType>

至此,csdl部分修改完毕。

第三步,修改msl文件:

找到msl部分的定义,修改Customers部分的影射定义。具体代码以下(请注意ComplexProperty节):

<EntitySetMappingName="Customers">

            <EntityTypeMappingTypeName="IsTypeOf(NorthwindModel.Customers)">

              <MappingFragmentStoreEntitySet="Customers">

                <ScalarPropertyName="CustomerID"ColumnName="CustomerID" />

                <ScalarPropertyName="CompanyName"ColumnName="CompanyName" />

                <ScalarPropertyName="ContactName"ColumnName="ContactName" />

                <ScalarPropertyName="ContactTitle"ColumnName="ContactTitle" />

                <ComplexPropertyName="Address"TypeName="NorthwindModel.CommonAddress">

                  <ScalarPropertyName="Address"ColumnName="Address" />

                  <ScalarPropertyName="City"ColumnName="City" />

                  <ScalarPropertyName="Region"ColumnName="Region" />

                  <ScalarPropertyName="PostalCode"ColumnName="PostalCode" />

                  <ScalarPropertyName="Country"ColumnName="Country" />

                </ComplexProperty>

                <ScalarPropertyName="Phone"ColumnName="Phone" />

                <ScalarPropertyName="Fax"ColumnName="Fax" />

              </MappingFragment>

            </EntityTypeMapping>

  </EntitySetMapping>

至此,msl部分修改完毕

第四步:从新产生实体类文件。

咱们可使用EmdGen2工具来从新实体类.cs文件。具体操做以下:

将修改好的模型文件(edmx),拷贝到使用edmgen2.exe同目录下,而后在命令行中输入:

Edmgen2 /codegen cs NorthwindEnites.edmx

执行此命令后,会在当前的文件夹下生成一个NorthwindEnites.cs代码文件,也就是实体类的代码文件。将改文件更名为:NorthwindEnites.Designer.cs(这步主要是和edmx对应起来)。

而后,将NorthwindEnites.edmx和NorthwindEnites.Designer.cs文件添加到项目中。

至此,复合类型的修改完毕。

按照一样的修改过程,咱们能够给Employees也增长一个Address的复杂类型属性。

接下来,咱们看看具体使用代码:

l        查询:

[Test]

        publicvoid TestAddress()

        {

            using(var db = newNorthwindModel.NorthwindEntities1())

            {

                Console.WriteLine("GetFive customer addresss :");

                var cts = db.Customers.Take(5);

                foreach (var c in cts)

                {

                    Console.WriteLine("Address:{0},Country:{1},City:{2},PostalCode:{3}",c.Address.Address, c.Address.Country, c.Address.City, c.Address.PostalCode);

                }

                Console.WriteLine("GetFive Employess address:");

                var emp = db.Customers.Take(5);

                foreach(var c in emp)

                {

                    Console.WriteLine("Address:{0},Country:{1},City:{2},PostalCode:{3}",c.Address.Address, c.Address.Country, c.Address.City, c.Address.PostalCode);

                }

            }

        }

l        添加:

[Test]

        publicvoid AddTest()

        {

            using(var db = newNorthwindModel.NorthwindEntities1())

            {

                var customer = newNorthwindModel.Customers

                {

                    CustomerID = "2009",

                    CompanyName = "Complex Company",

                    ContactName = "xray2005",

                    Address = new NorthwindModel.CommonAddress

                    {

                        Address = "SiChuan,China",

                        City = "ChengDou",

                        Country = "China",

                        PostalCode ="610041",

                        Region = "Chenghua"

                    }

                };

               db.AddToCustomers(customer);

                db.SaveChanges();

                var cst = db.Customers.FirstOrDefault(c =>c.CustomerID == "2009");

                Assert.IsNotNull(cst);            

                Console.WriteLine("CustomerID:{0},CompanyName:{1},ContactName:{2},City:{3},Country:{4}",cst.CustomerID, cst.CompanyName, cst.ContactName, cst.Address.City,cst.Address.Country);

            }

        }

l        条件查询:

[Test]

        publicvoid QueryTest()

        {

            using(var db = newNorthwindModel.NorthwindEntities1())

            {

                var cst = db.Customers.FirstOrDefault(c =>c.Address.City == "ChengDou");

                Assert.IsNotNull(cst);      

                Console.WriteLine("CustomerID:{0},CompanyName:{1},ContactName:{2},City:{3},Country:{4}",cst.CustomerID, cst.CompanyName, cst.ContactName, cst.Address.City,cst.Address.Country);

            }

        }

最后,补充说明:

1,  在VS的可视化设计器里,不支持复杂类型,因此修改后没法再在可视化设计器里修改模型(edmx文件)。

2,  复杂类型不能单独存在,它必须和某一实体相关起来。

3,  复杂类型不能包含导航属性,如导航到实体或实体集。

4,  复杂类型具备内部结构但没有 Key(主键) 属性的数据类型

下面是示例代码和EdmGen2工具的链接。

示例代码  EdmGen2

 

Entity Framework 学习中级篇2—存储过程()

 

目前,EF对存储过程的支持并不完善。存在如下问题:

l        EF不支持存储过程返回多表联合查询的结果集。

l        EF仅支持返回返回某个表的所有字段,以便转换成对应的实体。没法支持返回部分字段的状况。

l        虽然能够正常导入返回标量值的存储过程,可是却没有为咱们自动生成相应的实体.cs代码,咱们仍是没法在代码中直接调用或使用标量存储过程

l        EF不能直接支持存储过程当中Output类型的参数。

l        其余一些问题。

下面,主要针对如何使用存储过程,以及存储返回实体、表的部分字段这个几个问题,作具体介绍。

l         导入存储过程及返回实体

在VS可视化设计器中,打开实体模型(emdx文件)。而后,鼠标右键点击“Customers”à “添加”à“函数导入”,而后选择“存储过程名称”,并输入函数导入名称,选择返回类型为实体并选择Customers。以下图所示:

 

以后,点击“肯定”。以后,存储过程导入。在代码咱们就可使用改存储过程了。以下代码所示:

[Test]

        public voidGetEntityBySP()

        {

           using (var db =new NorthwindEntities())

           {

               var cst = db.GetCustomerById("ALFKI").FirstOrDefault();

               Assert.IsNotNull(cst);

               Console.WriteLine("CustomerId:{0},ContactName:{1}",cst.CustomerID, cst.ContactName);

           }

        }

l         联合查询结果集的问题

在此版本的EF中,是不支持存储过程的多张表联合查询的,也就是说查询的结果集中,一部分字段来自表A,另外一部分字段来自表B,像这种状况,目前EF没法直接进行处理。为此,能够经过写两个或多个存储过程来实现。好比:第一个存储过程返回表A的全部字段,第二存储过程返回表B的全部字段;而后,咱们在代码中来实现联合的查询。

按照前面的思路,增长一个返回全部的Orders表字段的存储过程GetOrdersByCustomerId,再增长一个返回Order Details表所有字段的存储过程GetDetailsByCustomerId,并将它们导入到实体模型中。

其中,GetOrdersByCustomerId存储过程以下:

CREATE PROCEDURE GetOrdersByCustomerId

        @CustomerId varchar(5)

AS

BEGIN

        SET NOCOUNT ON;

        SELECT * FROM orders WHEREorders.CustomerID=@CustomerId;

END

GetDetailsByCustomerId存储过程以下:

CREATE PROCEDURE GetDetailsByCustomerId

@CustomerIdvarchar(5)       

AS

BEGIN

        SET NOCOUNT ON;

        SELECT d.*

     FROM  Orders o,[Order Details] d

        WHERE o.OrderId=d.OrderId  AND o.CustomerId=@CustomerId;

END

以后,在咱们的代码来实现联合查询。代码以下:

[Test]

        public voidGetOrderBySp()

        {

           using (var db =new NorthwindEntities())

           {

               var orders = db.GetOrdersByCustomerId("VINET").ToList();

               var details = db.GetDetailsByCustomerId("VINET").ToList();

               orders.ForEach(o =>o.Order_Details.Attach(details.Where(d => d.OrderID == o.OrderID)));

               foreach (varorder in orders)

               {

                   Console.WriteLine(order.OrderID);

                   foreach (var d in order.Order_Details)

                       Console.WriteLine(d.ProductID);

               }

           }

        }

其中,须要注意的,因为是分别执行了两个存储,在内存中是以两个对立的对象存在,它们以前是没有创建联系的。为此,咱们须要使用Attach方法来把他们联系起来(红色代码段),这样咱们就能够经过导航来访问对象的实体了,也就是foreach (var d in order.Order_Details)中的order.Order_Details。

l         返回部分字段的问题

默认状况,目前此版本的EF在使用存储过程返回实体的时候,必须返回全部的字段,以即是EF可以自动将返回的结果转换成对应的实体。不然会报“数据读取器与指定的XXX类型不兼容的异常,….”。

接下来,咱们经过创建一个存储过程,并创建新创建一个实体来解决此问题。首先,咱们在数据库中创建一个名为GetCustomerAndOrders的存储过程,其定义以下:

CREATE PROCEDURE GetCustomerAndOrders

    AS

BEGIN

    SET NOCOUNT ON;

    SELECTc.CustomerID,c.CompanyName,o.OrderID,o.OrderDate,d.Quantity

    FROMCustomers c,Orders o,[OrderDetails] d

    WHEREc.CustomerID=o.CustomerID AND o.OrderID=d.OrderID;

END

GO

而后,添加一个实体CustomerOders,并设置属性以下图所示:

 

而后,在VS可视化设计器中,打开实体模型(emdx文件),经过添加à函数导入,导入存储过程GetCustomerAndOrders,并取名为GetCustomerAndOrders,返回类型设置为实体CustomerOrders。

最后,咱们就能够代码实体此实体和存储过程了。以下代码:

[Test]

        public voidGetOrderCountByCustomerId()

        {

           using (vardb = new NorthwindEntities())

           {

               var co =db.GetCustomerAndOrders().Take(10).Skip(0);

               foreach(var c in co)

                     Console.WriteLine(c.CustomerID);

           }

        }

l         返回标量值问题

目前,EF对存储过程返回标量值的支持并无彻底。虽然,咱们能够按照前面的步骤导入函数,并设置返回标量值的类型,同时EF会在实体模型文件为咱们自动生成此存储过程相关的映射配置等。可是,EF却没有为咱们生成在实体模型cs文件中,自动生成相应的.cs代码,因此咱们根本没法直接调用此存储过程。为解决此问题,咱们须要手动添加代码到实体模型的.cs代码文件中。

首先,在数据库中创建存储存储过程GetOrderCntByCustomerId,代码以下:

CREATE PROCEDUREGetOrderCntByCustomerId

        @CustomerId varchar(5)

AS

BEGIN

        SET NOCOUNT ON;

        SELECT count(*) FROM Orders WHERE Orders.CustomerId=@CustomerId;

END

接着,按照正常的步骤,导入此存储过程并设置返回类型为标量类型的Int32。

而后,咱们须要添加一个泛型的方法和一个执行存储过程的方法,代码以下:

public partial class NorthwindEntities

{

   //泛型方法用于执行标量存储过程

        private T ExecuteFunction<T>(string functionName, System.Data.EntityClient.EntityParameter[] parameters) where T : struct

        {

           System.Data.EntityClient.EntityCommand cmd =((System.Data.EntityClient.EntityConnection)this.Connection).CreateCommand();

           cmd.CommandType = System.Data.CommandType.StoredProcedure;

           cmd.Parameters.AddRange(parameters);

           cmd.CommandText = this.DefaultContainerName + "." + functionName;

           try

           {

               if (cmd.Connection.State != System.Data.ConnectionState.Open)

                   cmd.Connection.Open();

               var obj = cmd.ExecuteScalar();

               return (T)obj;

           }

           catch (System.Exception)

           {

               throw;

           }

           finally

           {

               cmd.Connection.Close();

           }

        }

        //执行数据库中GetOrderCntByCustomerId存储过程的方法

        public intGetOrderCountByCustomerId(string CustomerId)

        {

           var param = newSystem.Data.EntityClient.EntityParameter("CustomerId", System.Data.DbType.String);

           param.Value = CustomerId;

           return ExecuteFunction<int>("GetOrderCountByCustomerId",new[] { param });

        }

}

最后,经过以上修改,咱们就能够直接使用返回标量值的存储过程,代码以下:

[Test]

        public voidGetOrderCountByCustomerId()

        {

           using (var db =new NorthwindEntities())

           {

               var result = db.GetOrderCountByCustomerId("VINET");

               Assert.Greater(result, 0);

               Console.WriteLine(result.ToString());

           }

        }

至此,咱们就解决了EF存储过程返回标量的问题。

 

Entity Framework 学习中级篇3—存储过程()

 

目前,EF对存储过程的支持并不完善。存在如下问题:

l        EF不支持存储过程返回多表联合查询的结果集。

l        EF仅支持返回返回某个表的所有字段,以便转换成对应的实体。没法支持返回部分字段的状况。

l        虽然能够正常导入返回标量值的存储过程,可是却没有为咱们自动生成相应的实体.cs代码,咱们仍是没法在代码中直接调用或使用标量存储过程

l        EF不能直接支持存储过程当中Output类型的参数。

l        其余一些问题。

本节,咱们将学习如何手动添加/修改存储过程,如何使EF可以支持Output类型的参数。

l         添加/修改存储过程

有时候,某个SQL语句比较复杂,可是数据库中又没有定义相应的存储过程。这个时候,咱们又想使上层代码比较简单、方便的方式来完成此项任务。那么,此时,咱们即可以手工在实体模型(.edmx文件)中添加本身须要的存储过程了。这样既方便上层调用又方便后期的修改。

以手动修改实体模型edmx文件,添加名为CustomerByCommandText的存储过程为例。具体步骤以下:

修改实体模型文件,找到ssdl部分,添加以下代码:

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

         <CommandText>

           select c.* from Customers c,Orders o where c.CustomerID=o.CustomerID

         </CommandText>

       </Function>

而后,再找到csdl部分,添加以下代码:

<FunctionImport Name="CustomerByCommandText" EntitySet="Customers" ReturnType="Collection(NorthwindModel.Customers)"></FunctionImport>

接着,找到msl部分,添加以下代码:

<FunctionImportMapping FunctionImportName="CustomerByCommandText" FunctionName="NorthwindModel.Store.CustomerByCommandText"/>

最后,在实体模型的.cs文件里面,添加一个执行此存储过程的方法,代码以下:

        public global::System.Data.Objects.ObjectResult<Customers>GetCustomerByCommandText()

        {

           return base.ExecuteFunction<Customers>("CustomerByCommandText");

        }

至此,修改完毕。

如今,咱们就能够在代码使用刚才手工定义的存储过程了。以下代码所示:

[Test]

        public voidGetCustomerByCmdText()

        {

           using (var db =new NorthwindEntities())

           {

               var csts =db.GetCustomerByCommandText().Take(10).Skip(0);

               foreach (var c in csts)

                   Console.WriteLine(c.CustomerID);

           }

        }

其实,关键的地方就是CommandText这个部分的内容,它里面就是要执行的SQL语句。另外,咱们能够在修改实体模型emdx文件的同时,咱们能够看到全部的实体类查询的SQL语句命令均可以在edmx文件里找到,咱们均可以进行相应的修改。

l         Output类型参数

在实际应用当中,不少时候,咱们须要使用output类型的存储过程参数,以便返回咱们须要的值。可是,目前,EF不能直接支持output类型的存储过程参数。为此,咱们须要对实体模型进行修改,以便使其支持output类型的输出参数。具体过程以下:

在数据库中创建一个为名的GetNameByCustomerId存储过程,代码以下:

CREATE PROCEDURE GetNameByCustomerId

 @CustomerId varchar(5),

 @ContactName varchar(30) output

AS

BEGIN

 SET NOCOUNT ON;

 SELECT @ContactName=ContactName

 FROM Customers

 WHERE CustomerID=@CustomerId;

END

而后,开始修改实体模型edmx文件。

先找到ssdl定义的部分,添加以下代码:

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

         <Parameter Name="CustomerId" Type="varchar" Mode="In" MaxLength="5"></Parameter>

         <Parameter Name="ContactName" Type="varchar" Mode="Out" MaxLength="30"></Parameter>

       </Function>

接着,在找到csdl定义的部分,添加以下代码:

      <FunctionImport Name="GetNameByCustomerId">

           <Parameter Name="CustomerId" Mode="In" Type="String" MaxLength="5"></Parameter>

           <Parameter Name="ContactName" Mode="Out" Type="String" MaxLength="30"></Parameter>

      </FunctionImport>

最后,找到msl定义的部分,添加以下代码:

<FunctionImportMapping FunctionImportName="GetNameByCustomerId" FunctionName="NorthwindModel.Store.GetNameByCustomerId"></FunctionImportMapping>

至此,实体模型emdx文件修改完毕。

接下来,咱们须要在实体模型的.cs文件中,增长相应的调用方法。代码以下:

    public partial class NorthwindEntities1

{

 

//执行GetNameByCustomerId的方法

        public voidGetNameByCustomerId(string CustomerId, out stringContactName)

        {

           ContactName= string.Empty;

           var Pars = newSystem.Data.EntityClient.EntityParameter[]

           {

               new System.Data.EntityClient.EntityParameter{ ParameterName="CustomerId", DbType=System.Data.DbType.String,Value=CustomerId},

               new System.Data.EntityClient.EntityParameter{ParameterName="ContactName", DbType=System.Data.DbType.String, Direction=System.Data.ParameterDirection.Output}

           };

           this.ExecuteNonQuery("GetNameByCustomerId",Pars);

           ContactName = Pars[1].Value.ToString();

 

        }

     

      //辅助方法,执行SQL命令

        private voidExecuteNonQuery(string functionName,System.Data.EntityClient.EntityParameter[]parameters)

        {

           System.Data.EntityClient.EntityCommand cmd =((System.Data.EntityClient.EntityConnection)this.Connection).CreateCommand();

           cmd.CommandType = System.Data.CommandType.StoredProcedure;

           cmd.Parameters.AddRange(parameters);

           cmd.CommandText = this.DefaultContainerName + "." + functionName;

           try

           {

               if (cmd.Connection.State != System.Data.ConnectionState.Open)

                   cmd.Connection.Open();

               cmd.ExecuteNonQuery();

           }

           catch (System.Exception)

           {

               throw;

           }

           finally

           {

               cmd.Connection.Close();

           }

        }

}

如今,全部的修改工做都作完了。接下来,咱们就能够在代码中直接调用此存储过程了。示例代码以下:

[Test]

        public voidOutputTest()

        {

           using (var db =new NorthwindModel.NorthwindEntities1())

           {

               string contactname = string.Empty;

               db.GetNameByCustomerId("ALFKI", out contactname);

               Assert.IsTrue(!string.IsNullOrEmpty(contactname));

               Console.WriteLine(contactname);

           }

        }

至此,咱们即可以使用Output类型的输出参数了。

 

Entity Framework 学习中级篇4—存储过程()

 

在EF中,各个实体的插入、更新和删除也都经过使用存储过程来完成,以便提升点性能。这个相似于数据集。其步骤是:先定义存储过程,而后在VS的可视化设计器,设置存储过程映射便可。

下面,觉得Supplier实体映射存储过程为例。

分别创建插入、更新和删除存储过程。

InsertSuppliers存储过程定义以下:

CREATE PROCEDURE [dbo].[InsertSuppliers]

    -- Add theparameters for the stored procedure here

@CompanyName nvarchar(40),

@ContactName nvarchar(30),

@ContactTitle nvarchar(30),

@Address nvarchar(60),

@City nvarchar(15),

@Region nvarchar(15),

@PostalCode nvarchar(10),

@Country nvarchar(15),

@Phone nvarchar(24),

@Fax nvarchar(24),

@HomePage ntext

AS

BEGIN

    -- SETNOCOUNT ON added to prevent extra result sets from

    --interfering with SELECT statements.

    SET NOCOUNT ON;

    INSERTINTO Suppliers(CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax,HomePage)

    VALUES(@CompanyName,@ContactName,@ContactTitle,@Address,@City,@Region,@PostalCode,@Country,@Phone,@Fax,@HomePage);

    SELECTSCOPE_IDENTITY()AS SupplierID;

END

DeleteSuppliers存储过程定义以下:

CREATE PROCEDURE [dbo].[DeleteSuppliers]

    -- Add theparameters for the stored procedure here

@SupplierID int

AS

BEGIN

    -- SETNOCOUNT ON added to prevent extra result sets from

    --interfering with SELECT statements.

    SET NOCOUNT ON;

    DELETESuppliers WHERE SupplierID=@SupplierID

END

UpdateSuppliers存储过程定义以下:

CREATE PROCEDURE [dbo].[UpdateSuppliers]

 -- Add the parameters forthe stored procedure here

@SupplierID int,

@CompanyName nvarchar(40),

@ContactName nvarchar(30),

@ContactTitle nvarchar(30),

@Address nvarchar(60),

@City nvarchar(15),

@Region nvarchar(15),

@PostalCode nvarchar(10),

@Country nvarchar(15),

@Phone nvarchar(24),

@Fax nvarchar(24),

@HomePage ntext

AS

BEGIN

 -- SET NOCOUNT ON addedto prevent extra result sets from

 -- interfering withSELECT statements.

 SET NOCOUNT ON;

    UPDATESuppliers SET CompanyName=@CompanyName,ContactName=@ContactName,ContactTitle=@ContactTitle,Address=@Address,City=@City,Region=@Region,PostalCode=@PostalCode,Country=@Country,Phone=@Phone,Fax=@Fax,HomePage=@HomePage

 WHERE SupplierID=@SupplierID

END

而后,在VS可视化设计器中,打开实体模式edmx文件,而后在Suppliers实体上鼠标右键à“存储过程映射”,而后在在分别设置存储过程便可。以下图所示:

 

至此,存储过程映射完毕。咱们下面来具体的使用,代码以下:

使用存储过程Insert:

[Test]

        public voidSPInsert()

        {

           using (var db =new NorthwindEntities1())

           {

               var supplier = newSuppliers();

               supplier.CompanyName = "cnblogs";

               supplier.ContactName = "xray2005";

               supplier.ContactTitle = "net";

               supplier.City = "成都";

               supplier.Region = "四川";

               supplier.Country = "中国";

               supplier.PostalCode = "600041";

               supplier.Phone = "028-8001";

               supplier.Fax = "028-8002";

               supplier.HomePage = "http://xray2005.cnblogs.com";

               db.AddToSuppliers(supplier);

               db.SaveChanges();

 

           }

        }

使用存储过程Update:

        [Test]

        public voidSPUpdate()

        {

           using (var db =new NorthwindEntities1())

           {

               var supplier = db.Suppliers.FirstOrDefault(s=> s.SupplierID == 30);

               Assert.IsNotNull(supplier);

               supplier.CompanyName = "CNBLOGS";

               supplier.ContactName = "xray2005";

               supplier.ContactTitle= "♂风风车.net";

               supplier.City = "成都";

               supplier.Region = "四川";

               supplier.Country = "China";

               supplier.PostalCode = "600040";

               supplier.Phone = "028-1008611";

               supplier.Fax = "028-10086";

               supplier.HomePage = "http://www.cnblogs.com/xray2005";

               db.SaveChanges();

 

           }

        }

使用存储过程Delete:

        [Test]

        public voidSPDelete()

        {

           using(var db = new NorthwindEntities1())

           {

               var supplier = db.Suppliers.FirstOrDefault(s=> s.SupplierID == 31);

               Assert.IsNotNull(supplier);

               db.DeleteObject(supplier);

               db.SaveChanges();

               var supplier1 = db.Suppliers.FirstOrDefault(s=> s.SupplierID == 31);

               Assert.IsNull(supplier1);

           }

        }

至此,实体存储过程映射介绍完毕。本节,内容比较简单。

 

Entity Framework 学习中级篇5—使EF支持Oracle9i

 

从Code MSDN上下载下来的EFOracleProvider不支持Oracle9i.可是,目前我所使用的仍是Oracle9i。为此,对EFOracleProvider修改了如下,以便使其支持Oracle9i.

下面说说具体修改地方.(红色部分为添加或修改的代码部分)

一,修改EFOracleProvider

1,修改EFOracleProviderManifest.cs类文件,

 

internal const string TokenOracle9i ="9i";//addby xray2005

        internal const string TokenOracle10g = "10g";

        internal const string TokenOracle11g = "11g";

如下两个地方,不修改也是能够的.但考虑目前我主要是使用9i,因此也就修改为9i了.

        private EFOracleVersion_version = EFOracleVersion.Oracle9i; //EFOracleVersion.Oracle11g;

        private string _token= TokenOracle9i; //TokenOracle10g;

 

2,修改EFOracleVersion.cs类文件,以下代码所示:

namespace EFOracleProvider

{

    usingSystem;

    ///<summary>

    /// This enum describes the current storage version

    ///</summary>

    internalenum EFOracleVersion

    {

         Oracle9i = 9, //addby xray2005

        /// < summary>

        /// Oracle10g

        /// < /summary>

        Oracle10g = 10,

 

        /// < summary>

        /// Oracle 11g

        /// < /summary>

        Oracle11g = 11,

        // higher versions go here

    }

    ///<summary>

    /// This class is a simple utility class that determines theversion from the

    /// connection

    ///</summary>

    internalstatic class EFOracleVersionUtils

    {

        /// < summary>

        /// Get the version fromthe connection.

        /// < /summary>

        /// < paramname="connection">currentconnection</param>

        /// < returns>version for the current connection</returns>

        internal static EFOracleVersion GetStorageVersion(EFOracleConnection connection)

        {

           string serverVersion =connection.ServerVersion;

           if (serverVersion.StartsWith("9."))

           {

               return EFOracleVersion.Oracle9i; //add by xray2005

           }

           else if(serverVersion.StartsWith("10."))

           {

               return EFOracleVersion.Oracle10g;

           }

           else if(serverVersion.StartsWith("11."))

           {

               return EFOracleVersion.Oracle11g;

           }

           throw new ArgumentException("Couldnot determine storage version; " +

                   "a valid storage connection or a version hintis required.");

        }

        internal static string GetVersionHint(EFOracleVersionversion)

        {

           switch (version)

           {

               case EFOracleVersion.Oracle9i:

                   return EFOracleProviderManifest.TokenOracle9i; //add by xray2005

               case EFOracleVersion.Oracle10g:

                   return EFOracleProviderManifest.TokenOracle10g;

               case EFOracleVersion.Oracle11g:

                   return EFOracleProviderManifest.TokenOracle11g;

               default:

                   throw new ArgumentException("Couldnot determine storage version; " +

                           "a valid storage connection or a version hintis required.");

           }

        }

        internal static EFOracleVersion GetStorageVersion(string versionHint)

        {

           if (!string.IsNullOrEmpty(versionHint))

           {

               switch (versionHint)

               {

                   case EFOracleProviderManifest.TokenOracle9i:

                       return EFOracleVersion.Oracle9i; //add by xray2005

                   case EFOracleProviderManifest.TokenOracle10g:

                       return EFOracleVersion.Oracle10g;

                   case EFOracleProviderManifest.TokenOracle11g:

                       return EFOracleVersion.Oracle11g;

               }

           }

           throw new ArgumentException("Couldnot determine storage version; " +

                   "a valid storage connection or a version hintis required.");

        }

 

        internal static bool IsVersionX(EFOracleVersionstorageVersion)

        {

           return storageVersion == EFOracleVersion.Oracle9i ||storageVersion == EFOracleVersion.Oracle10g ||

               storageVersion == EFOracleVersion.Oracle11g; //add by xray2005

        }

    }

}

二,使用EFOracleProvider

修改完毕后,编译一下.若是是本身下载的源代码编译的,那么编译后的EFOracleProvider自动已经在GAC注册了.若是是手动注册EFOracleProvider到GAC,那么命令以下:

gacutil –I “EFOracleProvider.dll”

其中gacutil.exe位于:系统盘符号:\Program Files\Microsoft SDKs\Windows\v6.0A\bin下面。

接下来,咱们须要作的就是,把这个EFOracleProvider添加到Machine.config中.

第一步,找到Machine.config文件.该文件的位置在:

系统盘符号:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG下面.

第二步,用打开Machine.config文件,在DbProviderFactories配置节点,增长EFOracleProvider的配置,以下所示:

<DbProviderFactories>

      <add name="OdbcData Provider" invariant="System.Data.Odbc"description=".Net Framework Data Provider for Odbc"type="System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

      <addname="OleDb Data Provider" invariant="System.Data.OleDb"description=".Net Framework Data Provider for OleDb"type="System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

      <addname="OracleClient Data Provider"invariant="System.Data.OracleClient" description=".Net FrameworkData Provider for Oracle"type="System.Data.OracleClient.OracleClientFactory,System.Data.OracleClient, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

      <add name="SqlClientData Provider" invariant="System.Data.SqlClient"description=".Net Framework Data Provider for SqlServer"type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

      <addname="Microsoft SQL Server Compact Data Provider"invariant="System.Data.SqlServerCe.3.5" description=".NETFramework Data Provider for Microsoft SQL Server Compact"type="System.Data.SqlServerCe.SqlCeProviderFactory,System.Data.SqlServerCe, Version=3.5.0.0,Culture=neutral, PublicKeyToken=89845dcd8080cc91" />

     <addname="EF Oracle Data Provider" invariant="EFOracleProvider"description="EF Provider for Oracle"type="EFOracleProvider.EFOracleProviderFactory,EFOracleProvider, Version=1.0.0.0,Culture=neutral, PublicKeyToken=def642f226e0e59b"/>

</DbProviderFactories>

第三步,保存便可.

 

接下来,简单的介绍一下,如何使用这个EFOralceProvider.

第1步:在命令行窗口,将目录定位到提示符, 系统盘符:\WINDOWS\Microsoft.NET\Framework\v3.5.以下所示(是我电脑上的目录):

 

第2步,输入相应的生成参数.以下图所示:

 

“data source=test;user id=xray;password=123”成你本身的对应的参数便可.

肯定以后,就能够看到生成的结果了,同时会有写信息出来,以下示:

 

至此,EdmGen就为咱们生成须要的文件.生成的文件以下所示:

l           TestEFModel.csdl

l           TestEFModel.msl

l           TestEFModel.ssdl

l           TestEFModel.ObjectLayer.cs

l           TestEFModel.Views.cs

而后,经过EdmGen2工具, 使用刚刚生成的TestEFModel .csdl, TestEFModel .msl, TestEFModel .ssdl三个文件来生成一个模型.

命令以下:

Edmgen2.exe /toedmx TestEFModel.csdlTestEFModel.msl TestEFModel.ssdl

肯定以后,该工具就会为咱们生成一个TestEFModel.edmx文件了.

而后,把这个文件加入到咱们的项目中,同时修改项目的App.Config文件链接字符串,以下所示:

<?xmlversion="1.0" encoding="utf-8" ?>

<configuration>

 <connectionStrings>

   <add name="NorthwindEFModelContext"

         connectionString="provider=EFOracleProvider;

                          metadata=res://*/TestEFModel.csdl|res://*/TestEFModel.ssdl|res://*/TestEFModel.msl;

                          Provider Connection String='data source=test;user id=xray;password=1111'"

         providerName="System.Data.EntityClient"/>

 </connectionStrings>

</configuration>

最后保存.

至此,修改EFOracleProvider并使用,介绍完毕。

最后提供几个链接,以方便你们学习研究:

l           Code.MSDN上的EFOracleProvider

l           通过我修改后,支持Oracle9i的EFOracleProvider.dll

l           EdmGen2.exe 

 

Entity Framework 学习高级篇1—改善EF代码的方法(上)

 

本节,咱们将介绍一些改善EF代码的相关方法,如NoTracking,GetObjectByKey, Include等。

l         MergeOption.NoTracking

当咱们只须要读取某些数据而不须要删除、更新的时候,能够指定使用MergeOption.NoTracking的方式来执行只读查询(EF默认的方式是AppendOnly)。当指定使用NoTracking来进行只读查询时,与实体相关的引用实体不会被返回,它们会被自动设置为null。所以,使用NoTracking能够提高查询的性能。示例代码以下:

[Test]

        public voidNoTrackingTest()

        {

           using (var db =new NorthwindEntities1())

           {

//针对Customers查询将使用MergeOption.NoTracking

               db.Customers.MergeOption = MergeOption.NoTracking;

               var cust = db.Customers.Where(c => c.City =="London");

               foreach (var c in cust)

                   Console.WriteLine(c.CustomerID);

 

               //也能够这样写

               //var cust1 =((ObjectQuery<Customers>)cust).Execute(MergeOption.NoTracking);

 

               //Esql写法

               //string esql = "select value c from customersas c where c.CustomerID='ALFKI'";

               //db.CreateQuery<Customers>(esql).Execute(MergeOption.NoTracking).FirstOrDefault();

 

           }

        }

 

l         GetObjectByKey/First

GetObjectByKey

在EF中,使用GetObjectByKey方法获取数据时,它首先会查询是否有缓存,若是有缓存则从缓存中返回须要的实体。若是没有则查询数据库,返回须要的实体,并添加在缓存中以便下次使用。

First: 总从数据库中提取须要的实体。

所以,咱们应在合适的地方选择GetObjectByKey方法来获取数据,以减小对数据库的访问提高性能。示例代码以下:

[Test]

        public voidGetByKeyTest()

        {

           using (var db =new NorthwindEntities1())

           {

               //从数据库中提取数据

               var cst = db.Customers.First(c =>c.CustomerID == "ALFKI");

               Console.WriteLine(cst.CustomerID);

 

               //将从缓存中提取数据

               EntityKey key = newEntityKey("NorthwindEntities1.Customers","CustomerID", "ALFKI");

               var cst1 = db.GetObjectByKey(key) as Customers;

               Console.WriteLine(cst1.CustomerID);

 

 

           }

        }

此外,须要注意的是若是GetObjectByKey没有获取到符合条件的数据,那么它会抛异常。为了不此状况发生,在有可能出现异常的地方,咱们应该使用TryGetObjectByKey方法。TryGetObjectByKey方法获取数据的方式和GetObjectByKey相似,只是当没有取到符合条件的数据时,TryGetObjectByKey会返回null而不是抛异常。示例代码以下:

[Test]

        public voidTryGetByKeyTest()

        {

           using (var db =new NorthwindEntities1())

           {

 

               //没有符合条件的数据会有异常抛出

               EntityKey key = newEntityKey("NorthwindEntities1.Customers","CustomerID", "♂风车车.Net");

               var cst = db.GetObjectByKey(key) as Customers;

               Console.WriteLine(cst.CustomerID);

 

               //没有符合条件的数据会有返回null

               EntityKey key1 = newEntityKey("NorthwindEntities1.Customers","CustomerID", "♂风车车.Net");

               Object cst1 = null;

               db.TryGetObjectByKey(key1, out cst1);

               if (cst1 != null)

                   Console.WriteLine(((Customers)cst1).CustomerID);

 

           }

        }

 

l         First /FirstOrDefault

First: 当咱们使用First来获取数据,若是没有符合条件的数据,那么咱们的代码将会抛出异常。

FirstOrDefault: 当咱们使用FirstOrDefault来获取的数据,若是没有符合条件的数据,那么它将返回null。

显然,对于一个良好的代码,是对能够预见的异常进行处理,而不是等它本身抛出来。示例代码以下:

[Test]

        public voidFirstTest()

        {

           using (var db =new NorthwindEntities1())

           {

 

               //抛异常的代码

               var cst = db.Customers.First(c =>c.CustomerID == "♂风车车.Net");

               Console.WriteLine(cst.CustomerID);//此处将出抛异常

               

               //推荐的使用以下代码:

               var cst1 = db.Customers.FirstOrDefault(c =>c.CustomerID == "♂风车车.Net");

               if (cst1 != null)

                   Console.WriteLine(cst1.CustomerID);

           }

        }

l         延迟加载/Include

EF不支持实体的部分属性延迟加载,但它支持实体关系的延迟加载。默认状况,实体的关系是不会加载。以下代码:

[Test]

        public voidIncludeTest()

        {

           using(var db = new NorthwindEntities1())

           {

              var csts = db.Customers;

               foreach (var c in csts)

               {

                   Console.WriteLine(c.CustomerID);

                   foreach (var o in c.Orders)

                       Console.WriteLine("  " + o.OrderID);

               }

           }

        }

上述代码中,由于Orders没有被加载,因此在输出Orders的时候,是不会有任何输出的。

当咱们须要加载某些关联的关系时,但是用Include方法,以下代码所示:

[Test]

        public voidIncludeTest()

        {

           using (var db =new NorthwindEntities1())

           {

              var csts = db.Customers.Include("Orders");

               foreach (var c in csts)

               {

                   Console.WriteLine(c.CustomerID);

                   foreach (var o in c.Orders)

                       Console.WriteLine("  " + o.OrderID);

               }

           }

        }

上述代码中,Customers关联的Orders将被加载。

 

Entity Framework 学习高级篇2—改善EF代码的方法(下)

 

本节,咱们将介绍一些改善EF代码的方法,包括编译查询、存储模型视图以及冲突处理等内容。

l         CompiledQuery

提供对查询的编译和缓存以供从新使用。当相同的查询须要执行不少遍的时候,那么咱们可使用ComplieQuery将查询的语句进行编译以便下次使用,这样能够免去对同一语句的屡次处理,从而改善性能。

示例代码以下:

[Test]

        public voidComplieTest()

        {

           using (var db =new NorthwindEntities1())

           {

               //对查询进行编译

               var customer = CompiledQuery.Compile<NorthwindEntities1, IQueryable<Customers>>(

                   (database) => database.Customers.Where(c => c.City == "London"));

               

               //执行20次相同的查询

               for (int i = 0;i < 20; i++)

               {

                   DateTime dt = System.DateTime.Now;

                   foreach (var c in customer(db))

                       Console.WriteLine(c.CustomerID);

                   Console.WriteLine(DateTime.Now.Subtract(dt).TotalMilliseconds);

                   Console.WriteLine("---------------------------------------------------");

               }

 

            }

   }

l         存储模型视图

在EF中,当执行实体查询的时候,运行时首先将实体模型转换成ESQL视图,而ESQL视图则是根据msl文件来生成相应的代码。此外,ESQL视图包含了相应的查询语句。ESQL视图被建立后将在应用程序域中进行缓存以便下次使用。这个运行时生成存储模型视图是比较耗时的过程。

为了,免去运行时生成存储模型视图,咱们能够预先产生这个的存储模型视图。具体步骤以下:

首先,使用EdmGen2来产生存储模型视图,相应的命令以下:

Edmgen2 /ViewGen cs NorthwindEntites.edmx

执行此命令后,edmgen2会在当前目录下生成一个名为NorthwindEntites.GeneratedViews.cs这个文件,就是咱们要使用的存储模型视图文件。

将此文件添加到项目中就行,其余的代码不须要改变,EF会自动调用此视图文件。以下示例代码:

[Test]

        public voidViewTest()

        {

           using (var db =new NorthwindEntities1())

           {

               var suppliers = db.Suppliers;

               foreach (var s in suppliers)

                   Console.WriteLine(s.ContactName);

           }

        }

没有使用存储模型视图的状况是:

1 passed, 0 failed, 0 skipped, took 7.09seconds.

项目中添加了NorthwindEntites.GeneratedViews.cs文件,执行状况是:

1 passed, 0 failed, 0 skipped, took 5.38seconds.

可见,使用了存储模型视图的确是提升了性能。

l         冲突处理

在EF中,默认状况并不会检查并发冲突。由于EF实现的是乐观的并发模式,当有并发的冲突发生时,将会抛出Optimistic Concurrency Exception异常。咱们能够经过使用RefreshMode这个枚举来指定当发生冲突时如何处理。

RefreshMode有两中枚举值:

ClientsWins: 当提交修改,更新数据库中的值。

StoreWins: 放弃修改,使用数据库中的值。

示例代码片断以下:

var db2 = new NorthwindEntities1();

           var customer2 = db2.Customers.FirstOrDefault(c=> c.CustomerID == "2009");

           if (customer2 != null)

           {

               customer2.ContactName = "♂风车车.Net";

               customer2.City = "CD";

               customer2.Region = "GX";

           }

           try

           {

               db2.SaveChanges();

           }

           catch (OptimisticConcurrencyExceptionex) //捕获到冲突,则进行相应的处理

           {

               db2.Refresh(RefreshMode.ClientWins,customer2);

               db2.SaveChanges();

           }

上述代码片断,只是说明怎么处理并发冲突,不是具体的并发。(ps:原本是准备开个线程来模拟并发的,可是始终没成功,没明白什么缘由,望高人指点呢!)

 

Entity Framework 学习结束语

 

前一段时间,一直在学习EF.对于这个EF多少算是有点了解吧. 目前,对于EF这个学习系列的文章,就暂时写到这里.固然还有一些相关的知识没有介绍,请各位朋友见谅!很乐意和你们交换关于EF学习的心得或技巧.后续,关于EF块东西,我仍是会随时关注着,若是有什么好的心得或文章,我也会尽可能拿出来给你们分享!每次看到一些朋友的相关留言讨论,我都无比的兴奋,有点小小成就感!

       最后,感谢各位朋友的热情关注和支持!

 

     本文版权归做者全部,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。

相关文章
相关标签/搜索