(一) 前言                                                                  

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条件中的数据,不会进行全表查询。

我们以查询参数配置表为例。

查询代码如下:

  1. private void BindData()
  2. {
  3. var entitys = bll.GetPagedEntitys(Pager.CurrentPageIndex, Pager.PageSize, out RowCount, out PageCount, c => c.Deleted == false, false, c => c.Id);
  4.  
  5. BindRptData(rptList, entitys);
  6. Pager.RecordCount = RowCount;
  7. }

例一:Func<T, TResult>分页查询,代码如下:

  1. 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)
  2. {
  3. var temp = db.Set<T>().Where<T>(whereLambds);
  4. rows = temp.Count();
  5. totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ;
  6. temp = isAsc ? temp.OrderBy<T, S>(orderByLambds) : temp.OrderByDescending<T, S>(orderByLambds);
  7. temp = temp.Skip<T>(pageSize * (pageIndex - )).Take<T>(pageSize);
  8.  
  9. return temp.ToList<T>();
  10. }

用 SQL Server Profiler工具分析查询结果如下:

例二:Expression<Func<T, TResult>>分页查询,代码如下:

  1. 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)
  2. {
  3. var temp = db.Set<T>().Where<T>(whereLambds);
  4. rows = temp.Count();
  5. totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ;
  6. temp = isAsc ? temp.OrderBy<T, S>(orderByLambds) : temp.OrderByDescending<T, S>(orderByLambds);
  7. temp = temp.Skip<T>(pageSize * (pageIndex - )).Take<T>(pageSize);
  8.  
  9. return temp.ToList<T>();
  10. }

用 SQL Server Profiler工具分析查询结果如下:

(二) 陷阱二   EF SqlQuery方法拼接sql语句的陷阱                                  

说明:EF给开发者提供了SqlQuery方法直接拼接sql语句进行查询,这样既可以让开发者尽情的拼接sql,又可以使用EF提供的ORM将table转换成model。

然而如果使用不当也会造成在内存中分页的悲剧。

我们以查询公告表为例。

查询代码如下:

  1. private void BindData()
  2. {
  3. string where = GetQueryString(true);//自动组装过滤然后拼接sql查询条件--缺点是将业务逻辑放在了UI层(也可以在bll中做处理)。
  4. var entitys = bll.GetPagedEntitys(Pager.CurrentPageIndex, Pager.PageSize, out RowCount, out PageCount, where, "Id desc");
  5.  
  6. BindRptData(rptList, entitys);
  7. Pager.RecordCount = RowCount;
  8. //搜索后显示搜索条件
  9. Title_string_like.Value = GetQueryString("Title_string_like");
  10. FromWhere_string_like.Value = GetQueryString("FromWhere_string_like");
  11. AddTime_string_gt.Value = GetQueryString("AddTime_string_gt");
  12. AddTime_string_lt.Value = GetQueryString("AddTime_string_lt");
  13. }

关于第9行到第12行的功能可以参考博客:http://www.cnblogs.com/eggTwo/p/3682955.html

例三:SqlQuery方法结合Skip、Take分页查询,代码如下:

  1. public List<T> GetPagedEntitys(int pageIndex, int pageSize, out int rows, out int totalPage, string where, string orderKey, params object[] paramss)
  2. {
  3. string sqls = "select * from " + typeof(T).Name;
  4. if (!string.IsNullOrEmpty(where))
  5. {
  6. sqls = sqls + " where 1=1 " + where;
  7. }
  8. if (!string.IsNullOrEmpty(orderKey))
  9. {
  10. sqls += " order by " + orderKey;
  11. }
  12. var temp = db.Database.SqlQuery<T>(sqls, paramss);
  13. rows = temp.Count();
  14. if (rows % pageSize == )
  15. {
  16. totalPage = rows / pageSize;
  17. }
  18. else
  19. {
  20. totalPage = rows / pageSize + ;
  21. }
  22.  
  23. temp = temp.Skip(pageSize * (pageIndex - )).Take(pageSize);
  24. return temp.ToList<T>();
  25. }

用 SQL Server Profiler工具分析查询结果如下:

例四:SqlQuery方法row_number()函数自定义分页查询,代码如下:

  1. public List<T> GetPagedEntitys(int pageIndex, int pageSize, out int rows, out int totalPage, string where, string orderKey, params object[] paramss)
  2. {
  3.  
  4. string sqls = "";
  5. string tableName = typeof(T).Name;//获取表名
  6. string sql = string.Format("select *, row_number() over (order by {0} ) as row_number from {1}", string.IsNullOrEmpty(orderKey) ? "Id" : orderKey, tableName);
  7. string where1 = !string.IsNullOrEmpty(where) ? " where 1=1 " + where : "";
  8. int tag = (pageIndex - ) * pageSize;
  9. sqls = string.Format(@"select top ({0}) * from
  10. (
  11. {1}
  12. {2}
  13. ) as t
  14. where t.row_number > {3}", pageSize, sql, where1, tag);
  15. //获取数据
  16. var list = db.Database.SqlQuery<T>(sqls, paramss).ToList<T>();
  17.  
  18. //通过自定义的class R 取得总页码数和记录数
  19. string sqlCount = string.Format("select count(1) as Rows from {0} {1}", tableName, where1);
  20. rows = db.Database.SqlQuery<R>(sqlCount, paramss).ToList()[].Rows;
  21. totalPage = rows % pageSize == ? rows / pageSize : rows / pageSize + ;
  22.  
  23. return list;
  24.  
  25. }
  26. public class R
  27. {
  28. public int Rows { get; set; }
  29. }

说明:上述分页方法也是我全面改造EF分页查询的一个典范。从上述代码可以看出,这完全是自定义的拼接sql的分页查询,也就是说我们完全掌握了自主权。只是利用EF的ORM功能将table转换成model,其它的都是自己实现的。大家可能看到上述代码定义了一个类R,这是因为我们要查询总共的记录数。

用 SQL Server Profiler工具分析查询结果如下:

(三) 小结                                                  

以上叙述,就完成了几种EF分页的方式及陷阱的演示。如有错误或者不妥之处,欢迎指正。

EF分页中的陷阱的更多相关文章

  1. .NET Core使用EF分页查询数据报错:OFFSET语法错误问题

    在Asp.Net Core MVC项目中使用EF分页查询数据时遇到一个比较麻烦的问题,系统会报如下错误: 分页查询代码: ) * condition.PageSize).Take(condition. ...

  2. 存储过程分页 Ado.Net分页 EF分页 满足90%以上

    存储过程分页: create proc PR_PagerDataByTop @pageIndex int, @pageSize int, @count int out as select top(@p ...

  3. iOS下KVO使用过程中的陷阱 (转发)

    iOS下KVO使用过程中的陷阱   KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KV ...

  4. [小技巧]EF Core中如何获取上下文中操作过的实体

    原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...

  5. EF Core中避免贫血模型的三种行之有效的方法(翻译)

    Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...

  6. EF Core中的多对多映射如何实现?

    EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的.但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考<你必须掌握的Entity ...

  7. EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

    一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...

  8. 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx EF 6 ...

  9. 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...

随机推荐

  1. 如何从SharePoint Content DB中查询List数据

    SharePoint用来维护基础数据非常方便,只需要建立自定义列表,然后使用InfoPath自定义一下维护界面,就可以实现在线的增删改查,开发效率很高.如果维护的数据需要进行审批,还可以加入工作流功能 ...

  2. SQL Server调优系列基础篇(子查询运算总结)

    前言 前面我们的几篇文章介绍了一系列关于运算符的介绍,以及各个运算符的优化方式和技巧.其中涵盖:查看执行计划的方式.几种数据集常用的连接方式.联合运算符方式.并行运算符等一系列的我们常见的运算符.有兴 ...

  3. dotNET使用DRPC远程调用运行在Storm上的Topology

    Distributed RPC(DRPC)是Storm构建在Thrift协议上的RPC的实现,DRPC使得你可以通过多种语言远程的使用Storm集群的计算能力.DRPC并非Storm的基础特性,但它确 ...

  4. 以后上午就只能这样了么-jQuery

    hi 昨天睡得不错 为什么早上还是看不进论文,宁愿做这个,也不愿认真看论文.感觉上还是下午看论文感觉要好的多.不过最近有三十多篇要看哇...管球... 1.jQuery -----jQuery常用插件 ...

  5. LeetCode:Valid Sudoku,Sudoku Solver(数独游戏)

    Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku bo ...

  6. 《Invert》开发日志02:游戏风格定型

    声明:以下涉及到的<God of Light>.<Valiant Hearts : The Great War>.<Angry Birds 2>游戏截图均来自其Ap ...

  7. JAVA爬虫挖取CSDN博客文章

    开门见山,看看这个教程的主要任务,就去csdn博客,挖取技术文章,我以<第一行代码–安卓>的作者为例,将他在csdn发表的额博客信息都挖取出来.因为郭神是我在大学期间比较崇拜的对象之一.他 ...

  8. 洛谷U4727小L的二叉树[树转序列 LIS]

    题目背景 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣. 所以,小L当时卡在了二叉树. 题目描述 在计算机科学中,二叉树是每个结点最多有两个子结点的 ...

  9. AC日记——元素查找 codevs 1230

    1230 元素查找  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 给出n个正整数,然后有 ...

  10. Flash 二进制传图片到后台Java服务器接收

    需求:把客户端处理过的图片返还给服务器Flash端代码 01 package {02     import com.adobe.images.JPGEncoder;    03     import  ...