本文介绍一些改善EF代码、优化其性能的相关方法,如NoTracking,GetObjectByKey, Include等,还包括编译查询、存储模型视图以及冲突处理等内容。。

l         MergeOption.NoTracking

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

[Test]

       public void NoTrackingTest()
       {
           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 customers as c where c.CustomerID='ALFKI'";
               //db.CreateQuery<Customers>(esql).Execute(MergeOption.NoTracking).FirstOrDefault();
 
           }

}

l         GetObjectByKey/First

GetObjectByKey:
在EF中,使用GetObjectByKey方法获取数据时,它首先会查询是否有缓存,如果有缓存则从缓存中返回需要的实体。如果没有则查询数据库,返回需要的实体,并添加在缓存中以便下次使用。
First: 总从数据库中提取需要的实体。
因此,我们应在合适的地方选择GetObjectByKey方法来获取数据,以减少对数据库的访问提升性能。示例代码如下:

[Test]

       public void GetByKeyTest()
       {
           using (var db = new NorthwindEntities1())
           {
               //从数据库中提取数据
               var cst = db.Customers.First(c => c.CustomerID == "ALFKI");
               Console.WriteLine(cst.CustomerID);
 
               //将从缓存中提取数据
               EntityKey key = new EntityKey("NorthwindEntities1.Customers", "CustomerID", "ALFKI");
               var cst1 = db.GetObjectByKey(key) as Customers;
               Console.WriteLine(cst1.CustomerID);
 
 
          }

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

[Test]

       public void TryGetByKeyTest()
       {
           using (var db = new NorthwindEntities1())
           {
 
               //没有符合条件的数据会有异常抛出
               EntityKey key = new EntityKey("NorthwindEntities1.Customers", "CustomerID", "♂风车车.Net");
               var cst = db.GetObjectByKey(key) as Customers;
               Console.WriteLine(cst.CustomerID);
 
               //没有符合条件的数据会有返回null
               EntityKey key1 = new EntityKey("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 void FirstTest()
       {
           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 void IncludeTest()
       {
           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 void IncludeTest()
       {
           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将被加载。
l         CompiledQuery

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

示例代码如下:
[Test]

       public void ComplieTest()
       {
           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 void ViewTest()
       {
           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.09 seconds.

项目中添加了NorthwindEntites.GeneratedViews.cs文件,执行情况是:
1 passed, 0 failed, 0 skipped, took 5.38 seconds.

可见,使用了存储模型视图的确是提高了性能。
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 (OptimisticConcurrencyException ex) //捕获到冲突,则进行相应的处理
           {
               db2.Refresh(RefreshMode.ClientWins, customer2);
               db2.SaveChanges();
           }
上述代码片段,只是说明怎么处理并发冲突,不是具体的并发。(ps:本来是准备开个线程来模拟并发的,但是始终没成功,没明白什么原因,望高人指点呢!)

优化EF性能的更多相关文章

  1. 第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题

    一. 开篇说明 EF的性能问题一直以来经常被人所吐槽,究其原因在于“复杂的操作在生成SQL阶段耗时长,且执行效率不高”,但并不是没有办法解决,从EF本身举几个简单的优化例子: ①:如果仅是查询数据,并 ...

  2. lnmp使用socket方式连接nginx优化php-fpm性能

    lnmp使用socket方式连接nginx优化php-fpm性能 Nginx连接fastcgi的方式有2种:TCP和unix domain socket 什么是Unix domain socket?- ...

  3. REORG TABLE命令优化数据库性能

    [转]DB2日常维护——REORG TABLE命令优化数据库性能     一个完整的日常维护规范可以帮助 DBA 理顺每天需要的操作,以便更好的监控和维护数据库,保证数据库的正常.安全.高效运行,防止 ...

  4. 优化TableView性能

    优化tableView性能(针对滑动时出现卡的现象) (2013-08-02 11:18:15) 转载▼ 标签: ios tableview it 分类: 技术文档 在iOS应用中,UITableVi ...

  5. DB2日常维护——REORG TABLE命令优化数据库性能

    一个完整的日常维护规范可以帮助 DBA 理顺每天需要的操作,以便更好的监控和维护数据库,保证数据库的正常.安全.高效运行,防止一些错误重复发生. 由于DB2使用CBO作为数据库的优化器,数据库对象的状 ...

  6. Citrix 服务器虚拟化之十三 Xenserver虚拟机内存优化与性能监控

    Citrix 服务器虚拟化之十三   Xenserver虚拟机内存优化与性能监控 XenServer的DMC通过自动调节运行的虚拟机的内存,每个VM分配给指定的最小和最大内存值之间,以保证性能并允许每 ...

  7. Redis 优化查询性能

    一次使用 Redis 优化查询性能的实践   应用背景 有一个应用需要上传一组ID到服务器来查询这些ID所对应的数据,数据库中存储的数据量是7千万,每次上传的ID数量一般都是几百至上千数量级别. 以前 ...

  8. IIS优化服务器性能导致QuartZ任务未运行

    问题: IIS 为优化服务器性能,会自动对它认为休眠的应用程序进行资源回收,资源回收将会导致网站应用程序关闭. 解决方案: 1.  设置闲置超时为0,固定回收时间间隔为0,即IIS不主动回收闲置进程 ...

  9. DB2日常维护——REORG TABLE命令优化数据库性能(转)

    [转]DB2日常维护——REORG TABLE命令优化数据库性能 一个完整的日常维护规范可以帮助 DBA 理顺每天需要的操作,以便更好的监控和维护数据库,保证数据库的正常.安全.高效运行,防止一些错误 ...

随机推荐

  1. 解决Sublime Text 3中文显示乱码(tab中文方块)问题,sublime tab乱码

    一.文本出现中文乱码问题 1.打开Sublime Text 3,按Ctrl+-打开控制行,复制粘贴以下python代码,然后回车运行. 2. 复制并粘贴如下代码: import urllib.requ ...

  2. perl命令+关键字

    来源: http://www.cnblogs.com/itech/archive/2012/11/01/2749666.html http://www.garybeene.com/vb/tut-per ...

  3. MyBatis-xml配置SQL文件中,传入List数组、基本类型String、int……、与自定义类型的方法

    //基本类型 @Override public String queryItemNumber(String packId) throws Exception { // TODO Auto-genera ...

  4. sql-删除delete涉及到三个表,这个时候就要使用from,比如这样

    delete y from dbo.XZXK_BANJIE b ,YJDC_YELLOWRED_CONTENT y , dbo.XZXK_SHOULI s where b.shoulioid=s.sh ...

  5. js中Object.__proto__===Function.prototype

    参考:http://stackoverflow.com/questions/650764/how-does-proto-differ-from-constructor-prototype http:/ ...

  6. on使用详解

    on()是bind(),live(),delegate()的替代品,1.7及1.7以后使用on() bind() 绑定元素 live() 为元素附加事件,匹配选择器的当前及未来的元素(比如由脚本创建的 ...

  7. Mishka and Interesting sum

    Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megabytes input ...

  8. C++调用C#之C++DLL调用C# COM控件

    1. 新建项目 这里我们使用ATL,来接受C# COM控件向外发送的事件. 2. 初始化ATL #include "stdafx.h" CComModule _module; BO ...

  9. SSH整合中为获取表单对象Action类实现的接口及拦截器配置

    保存员工或者用户信息时,以员工为例,是通过表单收集信息的,需要把这些信息赋给一个对象,然后保存到数据库中.对应的Action类须实现Preparable接口及ModelDriven接口,且在Actio ...

  10. Swift -> Optional嵌套 探讨

    准备运动:Optional 的介绍 王巍的<Swifter>一书中,介绍了一个有用的命令:在 LLDB 中输入 fr v -R foo,可以查看foo 这个变量的内存构成.我们稍后的分析将 ...