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) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...
随机推荐
- MySQL连接方式及大小写问题
一.连接数据库 在命令行连接MySQL有这两种方式,一种是使用命令行参数:另一种是将参数信息写入配置文件 1.命令行中使用参数 -u用户名 -p密码 -D数据库名 -P数据库服务端口 -s安静模式 ...
- Git详解之四:服务器上的Git
服务器上的 Git 到目前为止,你应该已经学会了使用 Git 来完成日常工作.然而,如果想与他人合作,还需要一个远程的 Git 仓库.尽管技术上可以从个人的仓库里推送和拉取修改内容,但我们不鼓励这样做 ...
- c#代码技巧
1.#region #endregion 1.#region 是一个分块预处理命令,主要用于编辑代码分段,在编译时会自动屏蔽,同时该指令可以使代码在VS代码编辑器中折叠或展开: 2.#region必须 ...
- CentOS7源码安装lamp
环境介绍 虚拟机 : VMware Workstation 14 Pro 镜像 : CentOS Linux release 7.4.1708 (Core) 物理机 : windows 7 64位 防 ...
- TurnipBit:和孩子一起动手DIY“滚动”的生日礼物
当孩子的生日来临之时,做父母的总是会为该为孩子准备什么礼物而烦恼.下面就教家长朋友们利用TurnipBit开发板DIY一份"特殊"的生日礼物,不仅能增加与孩子的互动性还能提升孩子在 ...
- Wechat 微信端调用“微信支付接口”的正确方式
微信端的项目中,比如微信商城之类的,肯定会涉及到微信支付这一块: 下面直接上详细的代码: var data = {--}; // 调用微信支付需要的数据 function onBridgeReady( ...
- 腾讯云负载均衡CLB的那些“独门利器”
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:李想 腾讯人做产品一直是很贴近用户的需求的,腾讯云也不例外.负载均衡器作为公有云上的最基础的网络服务,几乎每家云厂商都会提供,虽然负载均衡 ...
- 简单认识python cmd模块
0X00 前言 在早前用别人的工具时,发现有些大佬会用到交互式shell,那时候就挺好奇的,但是一直都没有看一下怎么做到的. 今天在翻p牛的博客的时候,看到他早之前写的一个工具就有用到交互式shell ...
- MySQL之表操作
1 创建表 2 查看表结构 3 数据类型 4 表完整性约束 5 修改表 6 复制表 7 删除表 一创建表 语法: create table 表名( 字段名1 类型[(宽度) 约束条件], 字段名2 ...
- Chris Richardson微服务翻译:微服务之事件驱动的数据管理
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理(本文) 微服 ...