本文介绍一些改善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. MySQL性能优化的最佳21条经验【转载】

    今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据 ...

  2. 删除sql计划 调用的目标发生了异常。 (mscorlib) 其他信息: 用户 'sa' 登录失败。

    在删除以前创建的sql的计划任务时,弹出如题错误提示,发现错误原因在于,sa密码更改过,导致在删除时因为sa的密码和当前的密码不正确出现此错误. 解决办法: 1.在计划任务的编辑窗口,找到管理连接 2 ...

  3. linux查看文件及文件夹的大小

    最近发现服务器的磁盘容量使用率超过了90%,所以有必要查看是哪个文件占用了太多的空间, 服务器系统:CentOS6.5 df -h #查看磁盘使用情况,步骤1 cd / #切换到根目录, 步骤2 du ...

  4. 后台运行之BackgroundWorker

    BackgroundWorker 类允许您在单独的专用线程上运行操作. 耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态. 如果您需要能进行响应的用户界 ...

  5. OpenGL ES着色器语言之操作数(官方文档第五章)

    OpenGL ES着色器语言之操作数(官方文档第五章) 5.1操作数 OpenGL ES着色器语言包含如下操作符. 5.2数组下标 数组元素通过数组下标操作符([ ])进行访问.这是操作数组的唯一操作 ...

  6. OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围

    OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)   所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...

  7. shell写多行到文件中

    用cat或者echo命令输入多行数据到指定文本 #!/bin/sh ( cat <<EOF start() { echo "start" } EOF ) > Ma ...

  8. <link rel="stylesheet" href="3.css"/> 链接方式

    <link rel="stylesheet" href="3.css"/> <!doctype html> <html> & ...

  9. LightOJ 1030 Discovering Gold(期望)

    Description You are in a cave, a long cave! The cave can be represented by a 1 x N grid. Each cell o ...

  10. 分类算法-----KNN

    摘要: 所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用她最接近的k个邻居来代表.kNN算法的核心思想是如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于 ...