加入收藏 | 设为首页 | 会员中心 | 我要投稿 江门站长网 (https://www.0750zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

你必须知道的EF知识和经验

发布时间:2016-10-29 02:52:30 所属栏目:教程 来源:站长网
导读:副标题#e# 注意:以下内容如果没有特别申明,默认使用的EF6.0版本,codefirst模式。 推荐MiniProfiler插件 工欲善其事,必先利其器。 我们使用EF和在很大程度提高了开发速度,不过随之带来的是很多性能低下的写法和生成不太高效的sql。 虽然我们可以使用SQL
副标题[/!--empirenews.page--]

注意:以下内容如果没有特别申明,默认使用的EF6.0版本,code first模式。

推荐MiniProfiler插件

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

我们使用EF和在很大程度提高了开发速度,不过随之带来的是很多性能低下的写法和生成不太高效的sql。

虽然我们可以使用SQL Server Profiler来监控执行的sql,不过个人觉得实属麻烦,每次需要打开、过滤、清除、关闭。

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

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

数据准备

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

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

foreach循环的陷进 

1.关于延迟加载

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

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

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

解决方案:

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

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

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

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

再看MiniProfiler的监控(瞬间101条sql变成了1条,这其中的性能可想而知。)

AutoMapper工具

上面我们通过Include显示的执行表的连接查询显然是不错的,但还不够。如果我们只需要查询数据的某些字段呢,上面查询所有字段岂不是很浪费内存存储空间和应用程序与数据库数据传输带宽。

我们可以:

对应监控到的sql:

我们看到生成的sql,查询的字段少了很多。只有我们显示列出来字段的和一个StudentId,StudentId用来连接查询条件的。

是的,这样的方式很不错。可是有没有什么更好的方案或方式呢?答案是肯定的。(不然,也不会在这里屁话了。)如果表字段非常多,我们需要使用的字段也非常多,导航属性也非常多的时候,这样的手动映射就显得不那么好看了。那么接下来我们开始介绍使用AutoMapper来完成映射:

注意:首先需要NuGet下载AutoMapper。

我们看到上面查询语句没有一个个的手动映射,而映射都是独立配置了。其中CreateMap应该是要写到Global.asax文件里面的。(其实也就是分离了映射部分,清晰了查询语句。细心的同学可能注意到了,这种方式还免去了主动Include)

我们看到了生成的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次。(按考试类型分类统计)

代码如下:

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

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

马上变1条。

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

发现这仅仅只是查询结果集合而已,其中的按考试类型来统计是程序拿到所有数据后在计算的(而不是在数据库内计算,然后直接返回结果),这样同样是浪费了数据库查询数据传输。

关于连接查询分组统计我们可以使用SelectMany,如下:

监控sql如下:(是不是简洁多了呢?)

关于SelectMany资料:

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

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

性能提升之AsNonUnicode

监控到的sql

(编辑:江门站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读