EF分页中的陷阱
(一) 前言
EF使用非常简单,但是如果使用不当就会误入EF陷阱中。下面讲解了几种分页方式的对比,以及各种方式的缺陷。
(二) 陷阱一 Expression<Func<T, TResult>> 和Func<T, TResult>的区别
说明:System.Linq.Expressions.Expression<Func<T, TResult>>和Func<T, TResult>是有很大区别的。Func<T,TResult> 本身就是一个委托(delegate),而Expression<Func<T,TResult>>确实一个表达式,只有在编译之后才 会变成委托,那么在EF中到底使用哪一个呢?又是为什么呢?如果我们写成Func<T,TResult>作为参数传递给 where方法进行Linq查询时,Entity FrameWork将会产生全表查询,将整个数据库表忠的数据加载到内存中,然后再内存中根据where中的条件进一步查询,而 Expression<Func<t,bool>>只是查询出来你where条件中的数据,不会进行全表查询。
我们以查询参数配置表为例。
查询代码如下:
private void BindData()
{
var entitys = bll.GetPagedEntitys(Pager.CurrentPageIndex, Pager.PageSize, out RowCount, out PageCount, c => c.Deleted == false, false, c => c.Id); BindRptData(rptList, entitys);
Pager.RecordCount = RowCount;
}
例一:Func<T, TResult>分页查询,代码如下:
public List<T> GetPagedEntitys<S>(int pageIndex, int pageSize, out int rows, out int totalPage, Func<T, bool> whereLambds, bool isAsc,Func<T, S> orderByLambds)
{
var temp = db.Set<T>().Where<T>(whereLambds);
rows = temp.Count();
totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ;
temp = isAsc ? temp.OrderBy<T, S>(orderByLambds) : temp.OrderByDescending<T, S>(orderByLambds);
temp = temp.Skip<T>(pageSize * (pageIndex - )).Take<T>(pageSize); return temp.ToList<T>();
}
用 SQL Server Profiler工具分析查询结果如下:

例二:Expression<Func<T, TResult>>分页查询,代码如下:
public List<T> GetPagedEntitys<S>(int pageIndex, int pageSize, out int rows, out int totalPage, Expression<Func<T, bool>> whereLambds, bool isAsc, Expression<Func<T, S>> orderByLambds)
{
var temp = db.Set<T>().Where<T>(whereLambds);
rows = temp.Count();
totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ;
temp = isAsc ? temp.OrderBy<T, S>(orderByLambds) : temp.OrderByDescending<T, S>(orderByLambds);
temp = temp.Skip<T>(pageSize * (pageIndex - )).Take<T>(pageSize); return temp.ToList<T>();
}
用 SQL Server Profiler工具分析查询结果如下:

(二) 陷阱二 EF SqlQuery方法拼接sql语句的陷阱
说明:EF给开发者提供了SqlQuery方法直接拼接sql语句进行查询,这样既可以让开发者尽情的拼接sql,又可以使用EF提供的ORM将table转换成model。
然而如果使用不当也会造成在内存中分页的悲剧。
我们以查询公告表为例。
查询代码如下:
private void BindData()
{
string where = GetQueryString(true);//自动组装过滤然后拼接sql查询条件--缺点是将业务逻辑放在了UI层(也可以在bll中做处理)。
var entitys = bll.GetPagedEntitys(Pager.CurrentPageIndex, Pager.PageSize, out RowCount, out PageCount, where, "Id desc"); BindRptData(rptList, entitys);
Pager.RecordCount = RowCount;
//搜索后显示搜索条件
Title_string_like.Value = GetQueryString("Title_string_like");
FromWhere_string_like.Value = GetQueryString("FromWhere_string_like");
AddTime_string_gt.Value = GetQueryString("AddTime_string_gt");
AddTime_string_lt.Value = GetQueryString("AddTime_string_lt");
}
关于第9行到第12行的功能可以参考博客:http://www.cnblogs.com/eggTwo/p/3682955.html
例三:SqlQuery方法结合Skip、Take分页查询,代码如下:
public List<T> GetPagedEntitys(int pageIndex, int pageSize, out int rows, out int totalPage, string where, string orderKey, params object[] paramss)
{
string sqls = "select * from " + typeof(T).Name;
if (!string.IsNullOrEmpty(where))
{
sqls = sqls + " where 1=1 " + where;
}
if (!string.IsNullOrEmpty(orderKey))
{
sqls += " order by " + orderKey;
}
var temp = db.Database.SqlQuery<T>(sqls, paramss);
rows = temp.Count();
if (rows % pageSize == )
{
totalPage = rows / pageSize;
}
else
{
totalPage = rows / pageSize + ;
} temp = temp.Skip(pageSize * (pageIndex - )).Take(pageSize);
return temp.ToList<T>();
}
用 SQL Server Profiler工具分析查询结果如下:

例四:SqlQuery方法row_number()函数自定义分页查询,代码如下:
public List<T> GetPagedEntitys(int pageIndex, int pageSize, out int rows, out int totalPage, string where, string orderKey, params object[] paramss)
{ string sqls = "";
string tableName = typeof(T).Name;//获取表名
string sql = string.Format("select *, row_number() over (order by {0} ) as row_number from {1}", string.IsNullOrEmpty(orderKey) ? "Id" : orderKey, tableName);
string where1 = !string.IsNullOrEmpty(where) ? " where 1=1 " + where : "";
int tag = (pageIndex - ) * pageSize;
sqls = string.Format(@"select top ({0}) * from
(
{1}
{2}
) as t
where t.row_number > {3}", pageSize, sql, where1, tag);
//获取数据
var list = db.Database.SqlQuery<T>(sqls, paramss).ToList<T>(); //通过自定义的class R 取得总页码数和记录数
string sqlCount = string.Format("select count(1) as Rows from {0} {1}", tableName, where1);
rows = db.Database.SqlQuery<R>(sqlCount, paramss).ToList()[].Rows;
totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ; return list; }
public class R
{
public int Rows { get; set; }
}
说明:上述分页方法也是我全面改造EF分页查询的一个典范。从上述代码可以看出,这完全是自定义的拼接sql的分页查询,也就是说我们完全掌握了自主权。只是利用EF的ORM功能将table转换成model,其它的都是自己实现的。大家可能看到上述代码定义了一个类R,这是因为我们要查询总共的记录数。
用 SQL Server Profiler工具分析查询结果如下:

(三) 小结
以上叙述,就完成了几种EF分页的方式及陷阱的演示。如有错误或者不妥之处,欢迎指正。
EF分页中的陷阱的更多相关文章
- .NET Core使用EF分页查询数据报错:OFFSET语法错误问题
在Asp.Net Core MVC项目中使用EF分页查询数据时遇到一个比较麻烦的问题,系统会报如下错误: 分页查询代码: ) * condition.PageSize).Take(condition. ...
- 存储过程分页 Ado.Net分页 EF分页 满足90%以上
存储过程分页: create proc PR_PagerDataByTop @pageIndex int, @pageSize int, @count int out as select top(@p ...
- iOS下KVO使用过程中的陷阱 (转发)
iOS下KVO使用过程中的陷阱 KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KV ...
- [小技巧]EF Core中如何获取上下文中操作过的实体
原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...
- EF Core中避免贫血模型的三种行之有效的方法(翻译)
Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...
- EF Core中的多对多映射如何实现?
EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的.但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考<你必须掌握的Entity ...
- EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery
一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...
- 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx EF 6 ...
- 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...
随机推荐
- 数据库 SQL语句小结(更新中)
################ Navicat,单条执行sql ################ Navicat,数据库管理工具, 在查询的页面有好多命令,若单条执行: 1:可选中要执行的一条sql ...
- 单元测试中如何配置log4net
按道理来说,单元测试中基本没有对于日志的需求,这是由于单元测试的定位来决定的. 因为单元测试的思想就是针对的都是小段代码的测试,逻辑明确,如果测试运行不通过,简单调试一下,就能很容易地排查问题.但是单 ...
- Web API与国际化
软件国际化是在软件设计和文档开发过程中,使得功能和代码设计能处理多种语言和文化习俗,在创建不同语言版本时,不需要重新设计源程序代码的软件工程方法.这在很多成熟的软件开发平台中非常常见.对于.net开发 ...
- 打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个 "水仙花数 ",因为153=1的三次方+5的三次方+3的三次方。
---恢复内容开始--- ---恢复内容结束---
- Java设计模式 - 观察者模式
定义 观察者模式属于对象行为型模式. 在对象之间定义一对多的依赖,这样一来当一个对象改变状态,依赖它的对象都会收到通知并自动更新. 优点 1. 主题和观察者之间抽象耦合.无论什么对象主要实现了特定的 ...
- 【转】分布式数据层 TDDL 来自:阿里巴巴
淘宝根据自己的业务特点开发了TDDL(Taobao Distributed Data Layer 外号:头都大了 ©_Ob)框架,主要解决了分库分表对应用的透明化以及异构数据库之间的数据复制,它是一个 ...
- groups, usermod, chown, chgrp, chmod
Linux文件权限简介 Linux的每个文件可以由三种用户访问 属主权限:创建人的权限 属组权限:与创建同一个用户组的权限 其他权限:和创建人不在同一个用户组的用户的权限 当然,root用户拥有最高权 ...
- 在Windows下配置Python+Django+Eclipse开发环境
一.配置开发环境我的开发环境是:Python2.6.7 + Django1.6.2 + Eclipse1.安装Python2.安装Eclipse的Python插件PyDev如上两步如何操作请点击此进行 ...
- 怎么使PUTTY一直连接
如何才能保证PUTTY一直连接,即使我们好长时间不去敲命令,也让它一直连接着? PuTTY的设置方法是:在Connection里面有个Seconds between keepaliaves.这里就是每 ...
- yum简单安装apache
yum install httpd -y chkconfig httpd on service httpd start 启动软件