默认使用的EF6.0版本

【转】你必须清楚的EF知识和经验

注意:以下内容即便没有特意表明,默认使用的EF6.0版本,code first形式。

留神:以下内容假使没有特意表达,默认使用的EF6.0版本,code first格局。

推荐MiniProfiler插件

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

我们运用EF和在很大程度进步了开销进度,可是随着带动的是很多属性低下的写法和变化不太高速的sql。

虽说大家得以行使SQL Server
Profiler来监控执行的sql,然而个人认为就是麻烦,每一次需要打开、过滤、清除、关闭。

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

如图:(切切实进行使和介绍请移步)

公海赌船710 1

推荐MiniProfiler插件

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

我们接纳EF和在很大程度提升了开支速度,可是随后带动的是多多益善性能低下的写法和生成不太高速的sql。

即使我们可以动用SQL Server
Profiler来监控实施的sql,然而个人觉得就是麻烦,每一次需要开拓、过滤、清除、关闭。

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

如图:(实际使用和介绍请移步)

公海赌船710 2

数量准备

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

公海赌船710 3

后边会给出demo代码下载链接

数码准备

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

公海赌船710 4

背后会给出demo代码下载链接

foreach循环的陷进 

1.有关延迟加载

公海赌船710 5

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

公海赌船710 6

2.有关在循环中访问导航属性的特别处理(接着下面,加上virtual后会报以下非常)

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

公海赌船710 7

缓解方案:

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

3.以上两点仅为热身,我们说的陷阱才刚刚起初!

公海赌船710 8

然后我们点击打开MiniProfiler工具(不要被吓到)

公海赌船710 9

公海赌船710 10

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

公海赌船710 11

再看MiniProfiler的督查(弹指间101条sql变成了1条,这个中的特性显而易见。)

公海赌船710 12

foreach循环的陷进 

1.关于推迟加载

公海赌船710 13

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

公海赌船710 14

2.关于在循环中走访导航属性的不胜处理(接着下边,加上virtual后会报以下相当)

“已有开拓的与此 Command 相关联的
Data里德(Reade)r,必须首先将它倒闭。”

公海赌船710 15

化解方案:

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

3.以上两点仅为热身,大家说的牢笼才刚刚伊始!

公海赌船710 16

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

公海赌船710 17

公海赌船710 18

釜底抽薪方案:使用Include突显连续查询(注意:需要手动导入using System.Data.Entity
不然Include只可以传表名字符串)。

公海赌船710 19

再看MiniProfiler的监察(弹指间101条sql变成了1条,这之中的属性不问可知。)

公海赌船710 20

AutoMapper工具

下面大家透过Include显示的执行表的连天查询显著是不利的,但还不够。假设我们只需要查询数据的一点字段呢,下面查询所有字段岂不是很浪费内存存储空间和应用程序与数据库数据传输带宽。

我们可以:

公海赌船710 21

对应监督到的sql:

公海赌船710 22

咱俩看看变化的sql,查询的字段少了重重。只有大家呈现列出来字段的和一个StudentId,StudentId用来连接查询条件的。

正确,这样的措施很不利。然而有没有什么样更好的方案或方法吗?答案是肯定的。(不然,也不会在这里屁话了。)即便表字段很是多,我们需要动用的字段也不行多,导航属性也不行多的时候,这样的手动映射就彰显不那么窘迫了。那么接下去我们初叶介绍使用AutoMapper来形成映射:

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

公海赌船710 23

公海赌船710 24

俺们看来下边查询语句没有一个个的手动映射,而映射都是独自布置了。其中CreateMap应该是要写到Global.asax文件之中的。(其实也就是分手了炫耀部分,清晰了询问语句。细心的同室可能注意到了,这种办法还免去了主动Include)

公海赌船710 25

咱俩看看了扭转的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

AutoMapper工具

下边我们透过Include呈现的执行表的总是查询显明是不利的,但还不够。假设大家只需要查询数据的某些字段呢,下边查询所有字段岂不是很浪费内存存储空间和应用程序与数据库数据传输带宽。

大家得以:

公海赌船710 26

对应监督到的sql:

公海赌船710 27

俺们看到变化的sql,查询的字段少了无数。只有我们显示列出来字段的和一个StudentId,StudentId用来连接查询条件的。

科学,这样的方法很不利。不过有没有如何更好的方案或措施吧?答案是早晚的。(不然,也不会在此处屁话了。)假若表字段十分多,大家需要运用的字段也充裕多,导航属性也要命多的时候,这样的手动映射就显示不那么尴尬了。那么接下去咱们起先介绍使用AutoMapper来成功映射:

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

公海赌船710 28

公海赌船710 29

俺们看出地方查询语句没有一个个的手动映射,而映射都是独自布置了。其中CreateMap应该是要写到Global.asax文件之中的。(其实也就是分手了炫耀部分,清晰了询问语句。细心的同窗也许注意到了,那种办法还免去了当仁不让Include)

公海赌船710 30

我们看来了变动的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次。(按考试项目分类总括)

代码如下:

公海赌船710 31

来看如此的代码,我首先反响是惨了。又在循环执行sql了。监控如下:

公海赌船710 32

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

公海赌船710 33

马上变1条。

公海赌船710 34

大家开拓查看详细的sql语句

公海赌船710 35

发觉这仅仅只是查询结果集合而已,其中的按考试体系来总结是先后得到具备数据后在总括的(而不是在数据库内总计,然后径直回到结果),这样平等是荒废了数据库查询数据传输。

至于连接查询分组总括我们可以应用SelectMany,如下:

公海赌船710 36

监理sql如下:(是不是精简多了啊?)

公海赌船710 37

关于SelectMany资料:

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

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

联表查询总括

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

代码如下:

公海赌船710 38

看来如此的代码,我首先感应是惨了。又在循环执行sql了。监控如下:

公海赌船710 39

骨子里,我们只需要多少改变就把101条sql变成1条,如下:

公海赌船710 40

马上变1条。

公海赌船710 41

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

公海赌船710 42

察觉这仅仅只是查询结果集合而已,其中的按考试系列来总括是程序拿到具备数据后在统计的(而不是在数据库内总计,然后直接回到结果),这样同样是浪费了数据库查询数据传输。

关于连接查询分组总结我们可以动用SelectMany,如下:

公海赌船710 43

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

公海赌船710 44

关于SelectMany资料:

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

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

特性提高之AsNonUnicode

公海赌船710 45

监理到的sql

公海赌船710 46

大家看出EF正常情形变化的sql会在头里带上“N”,要是大家抬高DbFunctions.AsNonUnicode生成的sql是不曾“N”的,当您意识带上“N”的sql比没有带“N”的
sql查询速度慢很多的时候这就理解该咋做。

(往日用oracle的时候带不带“N”查询效用差距特别扎眼,前日用sql
server测试并没有发觉怎么区别公海赌船710 47。还有自己发觉EF6会按照数据库中是nvarchar的时候才会生成带“N”的sql,oracle数据库没测试,有趣味的同学能够测试下)

属性提升之AsNonUnicode

公海赌船710 48

督查到的sql

公海赌船710 49

大家看出EF正常情状变化的sql会在后面带上“N”,如果大家抬高DbFunctions.AsNonUnicode生成的sql是不曾“N”的,当您意识带上“N”的sql比没有带“N”的
sql查询速度慢很多的时候这就清楚该咋办。

(在此在此以前用oracle的时候带不带“N”查询效用差距特别显然,前日用sql
server测试并从未发觉怎么差距公海赌船710 50。还有我意识EF6会遵照数据库中是nvarchar的时候才会生成带“N”的sql,oracle数据库没测试,有趣味的同室可以测试下)

特性提高之AsNoTracking

公海赌船710 51

大家看变化的sql

公海赌船710 52

sql是生成的一模一样,可是执行时间却是4.8倍。原因仅仅只是第一条EF语句多加了一个AsNoTracking。

注意:

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

特性提高之AsNoTracking

公海赌船710 53

俺们看变化的sql

公海赌船710 54

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

注意:

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

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

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

公海赌船710 55

公海赌船710 56

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

公海赌船710 57

公海赌船710 58

不错不错,正是我们想要的效益。如若你不想用ThenBy,且都是升序的话,我们也足以:

公海赌船710 59

公海赌船710 60

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

看似好像很圆满了。其实不然,我们大部分动静排序是动态的。比如,大家会更为前端页面不同的操作要求不同字段的例外排序。那我们后台应该肿么办啊?

公海赌船710 61

本来,这样成功是没问题的,只要您愿意。可以这么多或者的论断有没有痛感特别SB?是的,大家当然有更好的解决方案。如果OrderBy可以直接传字符串???

解决方案:

  1. guget下载System.Linq.Dynamic 
  2. 导入System.Linq.Dynamic命名空间
  3. 编纂OrderBy的恢弘方法

公海赌船710 62

接下来上边又长又臭的代码能够写成:

公海赌船710 63

俺们看下生成的sql:

公海赌船710 64

和咱们想要的效劳完全符合,是不是感到美美哒!!

【注意】:传扬的排序字段前面要加排序关键字
asc或desc

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

务求:查询名字里面富含“张三”的学习者,先按名字排序,再按年龄排序。

公海赌船710 65

公海赌船710 66

咦,不对啊。按名字排序被年龄排序覆盖了。我们相应用ThenBy来整合排序。

公海赌船710 67

公海赌船710 68

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

公海赌船710 69

公海赌船710 70

变化的sql是同样的。与OrderBy、ThenBy对应的降序有OrderByDescending、ThenByDescending。

恍如好像很圆满了。其实不然,我们大部分情况排序是动态的。比如,我们会愈加前端页面不同的操作要求不同字段的不同排序。这大家后台应该肿么办吗?

公海赌船710 71

当然,这样成功是没问题的,只要您愿意。能够这么多或者的论断有没有痛感特别SB?是的,我们当然有更好的解决方案。假诺OrderBy可以直接传字符串???

釜底抽薪方案:

  1. guget下载System.Linq.Dynamic 
  2. 导入System.Linq.Dynamic命名空间
  3. 编制OrderBy的恢弘方法

公海赌船710 72

下一场下边又长又臭的代码可以写成:

公海赌船710 73

咱俩看下生成的sql:

公海赌船710 74

和我们想要的效用完全符合,是不是觉得美美哒!!

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

lamdba条件构成

要求:根据不同景色询问,可能情状

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

兑现代码:

公海赌船710 75

是不是味到了千篇一律的臭味公海赌船710 76。下边我们来灵活组装Lamdba条件。

缓解方案:

公海赌船710 77公海赌船710 78

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

然后我们的代码可以写成:

公海赌船710 79

有没有美美哒一点公海赌船710 80。然后我们看看生成的sql是否正确:

公海赌船710 81

lamdba条件构成

要求:依照不同景色询问,可能情状

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

心想事成代码:

公海赌船710 82

是不是味到了同样的臭气公海赌船710 83。下面大家来灵活组装Lamdba条件。

化解方案:

公海赌船710 84公海赌船710 85

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

接下来大家的代码可以写成:

公海赌船710 86

有没有美美哒一点公海赌船710 87。然后我们看看生成的sql是否正确:

公海赌船710 88

EF的预热

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

EF的预热

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

count(*)被你用坏了吗(Any的用法)

要求:查询是否留存名字为“张三”的学生。(你的代码会什么写吗?)

公海赌船710 89

首先种?第二种?第两种?呵呵,我原先就是应用的第一种,然后有人说“你count被您用坏了”,后来自我想了想了怎么就被自己用坏了吗?直到相比了这六个语句的属性后自己掌握了。

公海赌船710 90

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

俺们看出上边的Any干嘛的?官方表明是:

公海赌船710 91

自身一再阅读这一个中文演讲,一贯不可以了然。甚至早有人也提议过千篇一律的疑点《实则看不懂MSDN关于
Any
的诠释

于是自己个人了解也是“确定集合中是否有元素知足某一准绳”。大家来探视any其他用法:

要求:查询教过“张三”或“李四”的教职工

兑现代码:

公海赌船710 92

二种方法,往日我会习惯写第一种。当然大家看看生成过的sql和施行效能之后,看法改变了。

公海赌船710 93

频率之差竟有近六倍

我们再对照下count:

公海赌船710 94

公海赌船710 95

得出奇怪的下结论:

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

count(*)被你用坏了吗(Any的用法)

要求:查询是否留存名字为“张三”的学习者。(你的代码会如何写啊?)

公海赌船710 96

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

公海赌船710 97

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

大家来看地方的Any干嘛的?官方解释是:

公海赌船710 98

本人频繁阅读这个闽南语演说,平昔不能知晓。甚至早有人也指出过一样的疑问《实际看不懂MSDN关于
Any
的分解

就此自己个人知道也是“确定集合中是否有元素满足某一尺度”。我们来探望any其他用法:

务求:查询教过“张三”或“李四”的讲师

心想事成代码:

公海赌船710 99

两种艺术,以前我会习惯写第一种。当然我们看看生成过的sql和实践效率之后,看法改变了。

公海赌船710 100

频率之差竟有近六倍

俺们再对照下count:

公海赌船710 101

公海赌船710 102

得出奇怪的结论:

  1. 在导航属性之中使用count和动用any性能分别不大,反而FirstOrDefault()
    != null的章程性能最差。
  2. 在直接属性判断其中any和FirstOrDefault() !=
    null性能分别不大,count性能要差的多。
  3. 因此,不管是一贯属性依旧导航属性大家都用any来判定是否存在是最稳妥的。

晶莹剔透标识符

假使由于各类缘由我们需要写下边那样逻辑的口舌

公海赌船710 103

大家得以写成这样更好

公海赌船710 104

看生成的sql就知晓了

公海赌船710 105

其次种办法转变的sql要彻底得多,性能也更好。

晶莹剔透标识符

一经由于各样缘由我们需要写下面这样逻辑的说话

公海赌船710 106

咱俩得以写成这么更好

公海赌船710 107

看生成的sql就领悟了

公海赌船710 108

第三种艺术变通的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();//回滚事务
    }
}

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并不是说无法回滚,感谢@公海赌船710,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的壮大。

 公海赌船710 109

公海赌船710 110

 

补充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#基础知识巩固体系

欢迎热心园友补充!

自定义IQueryable扩大方法

 最后整理下自定义的IQueryable的恢弘。

 公海赌船710 111

公海赌船710 112

 

补充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#基础知识巩固体系

欢迎热心园友补充!

相关文章