Entity framework 中Where、First、Count等查询函数使用时要注意
在.Net开发中,Entity framework是微软ORM架构的最佳官方工具。我们可以使用Lambda表达式在Entity framework中DbSet<T>类上直接做查询(比如使用DbSet<T>类的Where、First、Count等查询函数)返回数据库结果实体。
不知道大家有没有注意到DbSet<T>类上的很多查询函数都有两种类型的重载,就拿Where这个查询函数举例:
一种是传入Func<Tsource, bool>委托作为参数
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
这种Where函数的重载返回的是IEnumerable<TSource>集合类型。
调用的示例如下面代码所示:
//CustomerDbContext为Entity framework中的DbContext
using (var customerDbContext = new CustomerDbContext())
{
//显示Entity framework底层调用的Sql语句到Visual Studio的输出窗口
customerDbContext.Database.Log = (message) => {
Debugger.Log(, "Sql", message);
}; Func<Mid_TriaBalance, bool> func = r => r.ID == ;//使用lambda表达式查询ID为1的数据库数据
var triaBalance = customerDbContext.Mid_TriaBalance.Where(func).First();
}
我们在上面的代码中使用了DbContext的Log委托,显示Entity framework生成的底层Sql语句到Visual Studio,运行该代码,我们来看看生成的Sql语句是什么,结果如下截图:
结果让人大跌眼镜,我们发现实际上Entity framework生成的Sql没有包含任何Where条件,是将整张Mid_TriaBalance表的数据都返回到C#代码后,再过滤出ID等于1的这一行数据。这种方式当Mid_TriaBalance表的数据比较少的时候还好,但是一旦Mid_TriaBalance表的数据很大比如100万行,那么我们为了查询ID为1的这一行数据,就需要将Mid_TriaBalance表中的100万行数据从数据库中取出先放到内存中,再去筛选ID为1的这一行数据,效率低下可想而知,还有可能造成服务器内存溢出。
一种是传入Expression<Func<TSource, bool>>类型作为参数:
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
这种Where函数的重载返回的是IQueryable<TSource>集合类型。
调用的示例如下面代码所示:
//CustomerDbContext为Entity framework中的DbContext
using (var customerDbContext = new CustomerDbContext())
{
//显示Entity framework底层调用的Sql语句到Visual Studio的输出窗口
customerDbContext.Database.Log = (message) => {
Debugger.Log(, "Sql", message);
}; Expression<Func<Mid_TriaBalance, bool>> exp = r => r.ID == ;//使用lambda表达式查询ID为1的数据库数据
var triaBalance = customerDbContext.Mid_TriaBalance.Where(exp).First();
}
同样我们在上面的代码中使用了DbContext的Log委托,显示Entity framework生成的底层Sql语句到Visual Studio,运行该代码,我们来看看生成的Sql语句是什么,结果如下截图:
这次我们看到Where函数使用Expression<Func<TSource, bool>>类型传入Lambda表达式后,Entity framework在底层生成了我们期望的Sql语句,包含了Where条件去限制数据库只查询ID为1的数据。很明显这种方式只会从数据库返回ID为1的一行数据到C#代码,效率和性能明显优于传入Func<Tsource, bool>委托的重载方式。
总结
我们可以看到这两种调用方式乍看之下觉得差别不大,最终都是返回Mid_TriaBalance表中ID为1的这一行数据。但是后台生成的Sql语句却有天壤之别,查询性能也有天壤之别。应该在Entity framework的Where、First、Count等查询函数中,避免使用传入Func<Tsource, bool>委托这种重载,因为这种重载在后台生的Sql语句中是不带任何Where限制条件的,是将整张表的数据先从数据库查出来后,放到C#代码内存中再做过滤,非常低效。
此外Expression<Func<TSource, bool>>类的构造函数无法直接调用,我们是无法去直接new一个Expression<Func<TSource, bool>>对象的,只有通过将lambda表达式直接赋值给Expression<Func<TSource, bool>>类型做隐式转换,C#会自动生一个Expression<Func<TSource, bool>>对象如下面代码所示:
Expression<Func<Mid_TriaBalance, bool>> exp = r => r.ID == ;//使用lambda表达式直接给Expression<Func<TSource, bool>>类型赋值,C#会帮助我们生成一个Expression<Func<TSource, bool>>对象
另外注意,不能将Func<TSource, bool>委托直接赋给Expression<Func<TSource, bool>>类型,这两种类型没法做类型转换,如下图所示,代码编译会报错:
Entity framework 中Where、First、Count等查询函数使用时要注意的更多相关文章
- entity framework 新手入门篇(3)-entity framework实现orderby,count,groupby,like,in,分页等
前面我们已经学习了entityframework的基本的增删改查,今天,我们将在EF中实现一些更加贴近于实际功能的SQL方法. 承接上面的部分,我们有一个叫做House的数据库,其中包含house表和 ...
- [转]在Entity Framework中使用LINQ语句分页
本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...
- Entity Framework 教程——Entity Framework中的实体类型
Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...
- Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询
Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询 SQL 中,有SQL Server Profiler可以用来查询性能以及查看外部调用的SQL ...
- 关于Entity Framework中的Attached报错的完美解决方案终极版
之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...
- Entity Framework学习笔记(六)----使用Lambda查询Entity Framework(1)
请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,老魏一直使用Linq来查询Entity Framework.但是老魏感觉,如果使用Linq的话,那么Linq的返回 ...
- Lazy<T>在Entity Framework中的性能优化实践
Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...
- Entity Framework中的几种加载方式
在Entity Framework中有三种加载的方式,分别是延迟加载,自动加载和显示加载.下面用一个例子来说明:现在有两个表,一个是资料表(Reference),另外一个表是资料分类表 ...
- 在Entity Framework 中实现继承关系映射到数据库表
继承关系映射到数据库表中有多种方式: 第一种:TPH(table-per-hiaerachy) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...
随机推荐
- jquery UI autocomplete当输入框焦点聚焦时自动弹出跟随下拉框
$("#search").autocomplete({ minLength: 0, source: function(request,response){ // request对象 ...
- 自定义tab吸顶效果一(原理)
PS:问题:什么是吸顶,吸顶有什么作用,吸顶怎么使用? 在很多app商城中,介绍软件的时候就会使用吸顶效果, 吸顶有很多作用,一个最简单粗暴的作用就是,让用户知道此刻在浏览哪个模块,并可以选择另外的模 ...
- [经验分享]WebApi+SwaggerUI 完美展示接口
不喜欢说废话,直接上干货. 第一步: 打开VS IDE ,新建一个WebAPI项目 选择Web .Net FrameWork (如果喜欢使用.Net Core的可以使用.Net Core) 选择Web ...
- 分享非常好用的前端分页js工具类 灵活 简单易懂
分享自己封装的前端分页js工具类 下面是默认样式效果截图 可以随意更改js及css 很灵活 /** * pageSize, 每页显示数 * pageIndex, 当前页数 * pageCount 总 ...
- centos yum源配置 与yum配置文件
参考博客 http://www.cnblogs.com/mchina/archive/2013/01/04/2842275.html 1.centos . yum配置文件在目录 /etc/yum.re ...
- 关于asp.net web form 和 asp.net mvc 的区别
asp.net web forms 有什么缺陷? 1.视图状态臃肿:服务器和客户端传输过程中包含了大量的试图状态——在现在的web程序中甚至多达几百kb,而且每次往返都会请求,导致服务器请求带宽增加, ...
- Linux中ls对文件进行按大小排序和按时间排序,设置ls时间格式
1 按文件大小排序 使用 ll -S | grep '^[^d]' // 格式化文件大小形式 ll -Sh | grep '^[^d]' 2 按文件修改时间排序显示 使用 ll -rt 3 设置ls ...
- 视频流GPU解码在ffempg的实现(二)-GPU解码器
1.gpu解码器的基本调用流程 要做视频流解码,必须要了解cuda自身的解码流,因为二者是一样的底层实现,不一样的上层调用 那cuda的解码流程是如何的呢 在https://developer.nvi ...
- HTML5新特性: 自定义属性前缀data-以及dataset的使用
HTML5规定可以为元素添加非标准的属性,但要添加前缀 data- ,目的是为元素提供与渲染无关的信息,或者提供语义信息.这些属性可以任意添加.随便命名,只要以 data- 开头即可 添加了自定义属性 ...
- angular4.0路由传递参数、获取参数最nice的写法
研究ng4的官网,终于找到了我想要的方法.我想要的结果是用'&'拼接参数传送,这样阅读上是最好的.否则很多'/'的拼接,容易混淆参数和组件名称.一般我们页面跳转传递参数都是这样的格式:http ...