您不可以不知道的EF知识和经验

【转】你不能不了然的EF知识和经历

注意:以下内容如若没有专门表达,默认使用的EF6.0版本,code first情势。

推荐MiniProfiler插件

工欲善其事,必先利其器。

我们使用EF和在很大程度提升了支出进度,不过随后带动的是无数属性低下的写法和扭转不太高速的sql。

虽说我们可以利用SQL Server
Profiler来监控执行的sql,不过个人觉得就是麻烦,每一次需要开拓、过滤、清除、关闭。

在此处强烈推荐一个插件MiniProfiler。实时监督页面请求对应实施的sql语句、执行时间。简单、方便、针对性强。

如图:(具体运用和介绍请移步)

亚洲必赢bwin696.com 1

数据准备

新建实体:Score(战表分数表)、Student(学生表)、Teacher(老师表)

亚洲必赢bwin696.com 2

末尾会给出demo代码下载链接

foreach循环的陷进 

1.有关推迟加载

亚洲必赢bwin696.com 3

请看上图红框。为啥StudentId有值,而Studet为null?因为运用code
first,需要设置导航属性为virtual,才会加载延迟加载数据。

亚洲必赢bwin696.com 4

亚洲必赢bwin696.com,2.关于在循环中走访导航属性的不得了处理(接着上边,加上virtual后会报以下分外)

“已有打开的与此 Command 相关联的
DataReader,必须首先将它倒闭。”

亚洲必赢bwin696.com 5

化解方案:

  • 方案1、设定ConnectionString加上MultipleActiveResultSets=true,但只适用于SQL
    2005将来的本子
  • 方案2、或者先读出放置在List中

3.之上两点仅为热身,我们说的牢笼才刚刚先导!

亚洲必赢bwin696.com 6

下一场大家点击打开MiniProfiler工具(不要被吓到)

亚洲必赢bwin696.com 7

亚洲必赢bwin696.com 8

解决方案:使用Include来得连续查询(注意:需要手动导入using System.Data.Entity
不然Include只可以传表名字符串)。

亚洲必赢bwin696.com 9

再看MiniProfiler的督察(瞬间101条sql变成了1条,这其间的性能总而言之。)

亚洲必赢bwin696.com 10

AutoMapper工具

地方我们透过Include突显的执行表的连天查询显明是不易的,但还不够。假设我们只需要查询数据的少数字段呢,上边查询所有字段岂不是很浪费内存存储空间和应用程序与数据库数据传输带宽。

咱俩得以:

亚洲必赢bwin696.com 11

对应监督到的sql:

亚洲必赢bwin696.com 12

咱俩看到变化的sql,查询的字段少了成千上万。只有大家来得列出来字段的和一个StudentId,StudentId用来连续查询条件的。

是的,这样的方法很科学。可是有没有咋样更好的方案或形式啊?答案是肯定的。(不然,也不会在此地屁话了。)尽管表字段相当多,我们需要采用的字段也要命多,导航属性也要命多的时候,这样的手动映射就呈现不那么美观了。那么接下去大家初始介绍使用AutoMapper来形成映射:

留神:首先需要NuGet下载AutoMapper。(然后导入命名空间 using
AutoMapper; using AutoMapper.QueryableExtensions;)

亚洲必赢bwin696.com 13

亚洲必赢bwin696.com 14

大家来看地点查询语句没有一个个的手动映射,而映射都是独立布置了。其中CreateMap应该是要写到Global.asax文件之中的。(其实也就是分别了炫耀部分,清晰了查询语句。细心的校友可能注意到了,这种模式还免去了积极向上Include)

亚洲必赢bwin696.com 15

大家看到了变化的sql和前边有些许两样,但只生成了一条sql,并且结果也是没错的。(其实就是多了一条CASE WHEN ([Extent2].[Id] IS
NOT NULL) THEN 1 END AS
[C1]。看起来这条语句并没有怎么实际意义,可是这是AutoMapper生成的sql,同时自身也意味着不晓得为何和EF生成的不同)

那样做的裨益?

  1. 避免在循环中做客导航属性多次执行sql语句。
  2. 避免了查询语句中太多的手动映射,影响代码的阅读。

有关AutoMapper的其它一些材料:

http://www.cnblogs.com/xishuai/p/3712361.html

http://www.cnblogs.com/xishuai/p/3700052.html

http://www.cnblogs.com/farb/p/AutoMapperContent.html

联表查询总计

务求:查询前100个学生考试连串(“模拟考试”、“正式考试”)、考试次数、语文平均分、学生姓名,且考试次数超越等于3次。(按考试项目分类总计)

代码如下:

亚洲必赢bwin696.com 16

总的来看这样的代码,我第一反应是惨了。又在循环执行sql了。监控如下:

亚洲必赢bwin696.com 17

其实,我们只需要有些改变就把101条sql变成1条,如下:

亚洲必赢bwin696.com 18

马上变1条。

亚洲必赢bwin696.com 19

俺们开辟查看详细的sql语句

亚洲必赢bwin696.com 20

发现这仅仅只是查询结果集合而已,其中的按考试项目来总计是先后得到拥有数据后在统计的(而不是在数据库内总括,然后径直回到结果),这样同样是浪费了数据库查询数据传输。

有关连接查询分组总计我们得以行使SelectMany,如下:

亚洲必赢bwin696.com 21

监察sql如下:(是不是精简多了吗?)

亚洲必赢bwin696.com 22

关于SelectMany资料:

http://www.cnblogs.com/lifepoem/archive/2011/11/18/2253579.html

http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html

特性进步之AsNonUnicode

亚洲必赢bwin696.com 23

监督到的sql

亚洲必赢bwin696.com 24

我们来看EF正常意况变化的sql会在头里带上“N”,即使大家添加DbFunctions.AsNonUnicode生成的sql是绝非“N”的,当你发现带上“N”的sql比一向不带“N”的
sql查询速度慢很多的时候这就驾驭该如何是好。

(以前用oracle的时候带不带“N”查询效用差异特别强烈,先天用sql
server测试并不曾意识什么样异样亚洲必赢bwin696.com 25。还有本人意识EF6会依据数据库中是nvarchar的时候才会生成带“N”的sql,oracle数据库没测试,有趣味的校友可以测试下)

性能提高之AsNoTracking

亚洲必赢bwin696.com 26

俺们看变化的sql

亚洲必赢bwin696.com 27

sql是变化的一模一样,不过实施时间却是4.8倍。原因仅仅只是第一条EF语句多加了一个AsNoTracking。

注意:

  • AsNoTracking干什么的吧?无跟踪查询而已,也就是说查询出来的对象不可能一直做修改。所以,大家在做多少集合查询彰显,而又不需要对聚集修改并更新到数据库的时候,一定毫无忘记加上AsNoTracking。
  • 尽管查询过程做了select映射就不需要加AsNoTracking。如:db.Students.Where(t=>t.Name.Contains(“张三”)).select(t=>new
    (t.Name,t.Age)).ToList();

多字段组合排序(字符串)

渴求:查询名字里面含有“张三”的学员,先按名字排序,再按年龄排序。

亚洲必赢bwin696.com 28

亚洲必赢bwin696.com 29

嗬,不对啊。按名字排序被年龄排序覆盖了。大家相应用ThenBy来构成排序。

亚洲必赢bwin696.com 30

亚洲必赢bwin696.com 31

不错不错,正是我们想要的效应。假设你不想用ThenBy,且都是升序的话,大家也得以:

亚洲必赢bwin696.com 32

亚洲必赢bwin696.com 33

转移的sql是一样的。与OrderBy、ThenBy对应的降序有OrderByDescending、ThenByDescending。

接近好像很全面了。其实不然,咱们大部分情景排序是动态的。比如,我们会愈来愈前端页面不同的操作要求不同字段的不同排序。这我们后台应该肿么办吧?

亚洲必赢bwin696.com 34

自然,这样成功是没问题的,只要你愿意。可以这样多或者的判断有没有觉得相当SB?是的,咱们自然有更好的缓解方案。若是OrderBy可以一向传字符串???

缓解方案:

  1. guget下载System.Linq.Dynamic 
  2. 导入System.Linq.Dynamic命名空间
  3. 编写OrderBy的壮大方法

亚洲必赢bwin696.com 35

然后上边又长又臭的代码可以写成:

亚洲必赢bwin696.com 36

大家看下生成的sql:

亚洲必赢bwin696.com 37

和大家想要的功力完全符合,是不是深感美美哒!!

【注意】:流传的排序字段后边要加排序关键字
asc或desc

lamdba条件构成

渴求:依据不同情形询问,可能情况

  1. 查询name=“张三” 的装有学生
  2. 询问name=“张三” 或者 age=18的拥有学生

落实代码:

亚洲必赢bwin696.com 38

是不是味到了同等的臭气亚洲必赢bwin696.com 39。上边大家来灵活组装Lamdba条件。

化解方案:

亚洲必赢bwin696.com 40亚洲必赢bwin696.com 41

这段代码我也是从网上偷的,具体链接找不到了。

下一场大家的代码可以写成:

亚洲必赢bwin696.com 42

有没有美美哒一点亚洲必赢bwin696.com 43。然后咱们看看生成的sql是否科学:

亚洲必赢bwin696.com 44

EF的预热

http://www.cnblogs.com/dudu/p/entity-framework-warm-up.html

count(*)被您用坏了啊(Any的用法)

务求:查询是否留存名字为“张三”的学童。(你的代码会怎么写吧?)

亚洲必赢bwin696.com 45

第一种?第二种?第两种?呵呵,我原先就是运用的首先种,然后有人说“你count被你用坏了”,后来自家想了想了怎么就被自己用坏了吧?直到比较了这六个语句的性能后我知道了。

亚洲必赢bwin696.com 46

性能之差竟有三百多倍,count确实被自己用坏了。(我想,不止被我一个人用坏了呢。)

俺们看看位置的Any干嘛的?官方表明是:

亚洲必赢bwin696.com 47

自我再三阅读这多少个普通话演讲,一向不能知道。甚至早有人也指出过千篇一律的疑云《其实看不懂MSDN关于
Any
的表明

故此我个人了解也是“确定集合中是否有元素满意某一标准化”。我们来看望any其他用法:

渴求:查询教过“张三”或“李四”的名师

实现代码:

亚洲必赢bwin696.com 48

二种艺术,以前我会习惯写第一种。当然我们看看生成过的sql和实施功用之后,看法改变了。

亚洲必赢bwin696.com 49

频率之差竟有近六倍

咱俩再对照下count:

亚洲必赢bwin696.com 50

亚洲必赢bwin696.com 51

得出奇怪的下结论:

  1. 在导航属性之中使用count和利用any性能分别不大,反而FirstOrDefault()
    != null的情势性能最差。
  2. 在直接属性判断其中any和FirstOrDefault() !=
    null性能分别不大,count性能要差的多。
  3. 故而,不管是平昔属性还是导航属性我们都用any来判断是否存在是最稳妥的。

晶莹剔透标识符

如若由于各个缘由我们需要写下边这样逻辑的话语

亚洲必赢bwin696.com 52

咱们得以写成这么更好

亚洲必赢bwin696.com 53

看生成的sql就知道了

亚洲必赢bwin696.com 54

第二种方法生成的sql要根本得多,性能也更好。

EntityFramework.Extended

这边推荐下插件EntityFramework.Extended,看了下,很正确。

最大的助益就是可以直接批量改动、删除,不用像EF默认的内需先做询问操作。

有关官方EF为啥没有提供这样的补助就不理解了。不过使用EntityFramework.Extended需要专注以下几点:

  1. 只支持sql server
  2. 批量改动、删除时不可能落实工作(也就是出了特别无法回滚)
  3. 尚无联级删除
  4. 不能同EF一起SaveChanges
    详见

http://www.cnblogs.com/GuZhenYin/p/5482288.html

在此纠正个问题EntityFramework.Extended并不是说不可以回滚,感谢@GuZhenYin园友的指正(原谅自己事先并未出手测试)。

在意:需要NuGet下载EntityFramework.Extended,
并导入命名空间: using
EntityFramework.Extensions ;

测试代码如下:(假诺注释掉手抛相当代码是可以直接更新到数据库的)

using (var ctxTransaction = db.Database.BeginTransaction())
{
    try
    {
        db.Teachers.Where(t => true).Update(t => new Teacher { Age = "1" });

        throw new Exception("手动抛出异常");

        ctxTransaction.Commit();//提交事务
    }
    catch (Exception)
    {
        ctxTransaction.Rollback();//回滚事务
    }
}

自定义IQueryable增加方法

 最后整理下自定义的IQueryable的扩大。

 亚洲必赢bwin696.com 55

亚洲必赢bwin696.com 56

 

补充1:

First和Single的区别:前者是TOP(1)后者是TOP(2),后者如果查询到了2条数据则抛出异常。所以在必要的时候使用Single也不会比First慢多少。

补充2: 

已打包nuget提供第一手设置 Install-Package
Talk.Linq.Extensions 或nuget搜索 Talk.Linq.Extensions 

https://github.com/zhaopeiym/Talk/wiki/Talk.Linq.Extensions_demo

 

结束:

源码下载:http://pan.baidu.com/s/1o8MYozw

正文以一头至《C#基础知识巩固系列

迎接热心园友补充!

相关文章