• Entity Framework返回IEnumerable还是IQueryable?


    在使用EF的过程中,我们常常使用repository模式,本文就在repository层的返回值是IEnumerable类型还是IQueryable进行探讨。

    阅读目录:

    一、什么是Repository模式?

    二、IEnumerable还是IQueryable的区别

    三、实际检验IEnumerable和IQueryable的效率差别

    四、总结

    一, 什么是Repository模式?

    Repository是隔离在数据访问层和业务逻辑层之间的。它提供业务逻辑各种对象,使得业务逻辑代码不需要关心数据是如何存储和获取的。

    下图,是MVC中使用Repository模式的模型图。Controller调用Repository来获取数据,而Repository调用EF来访问数据库。
    Repository模式的好处是它为逻辑和数据访问解耦,使得它们之间没有互相依赖。Repository可以挑选不同的数据来源,不如MySql, WCF, Web Service等,都不会影响到业务逻辑的改动。

    CRUD-using-the-Repository-Pattern-in-MVC-1 

    一段典型的Repository代码类似于:

    public class DailyReportRepository : IDailyReportRepository
    {
           private readonly Context _context;
    
           public DailyReportRepository(Context context)
           {
               _context = context;
           }
    
           public IQueryable<dailyreport> GetAllDailyReports()
           {
               return from report in _context.dailyreports
                      select report;
           }
    
          public IEnumerable<dailyreport> GetAllDailyReports(DateTime start, DateTime end)
           {
               var query = from report in GetAllDailyReports()
                           where
                              report.EntryDate >= start &&  report.EntryDate < end
                           select report;
    
               return query;
           }
    }

    二,IEnumerable还是IQueryable的区别

    上面的代码中,函数的返回值一个是IEnumerable类型,一个是IQuerable类型,它们有什么不同呢? 那个更好?

    IQueryable继承自IEnumerable,所以对于数据遍历来说,它们没有区别。

    但是IQueryable的优势是它有表达式树,所有对于IQueryable的过滤,排序等操作,都会先缓存到表达式树中,只有当真正遍历发生的时候,才会将表达式树由IQueryProvider执行获取数据操作。

    而使用IEnumerable,所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的。也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作。

    三,实际检验IEnumerable和IQueryable的效率差别

    Repository的代码如下, 返回同样的数据,一个使用IEnumerable,一个使用IQueryable

    public class StudentRepository : IStudentRepository
    {
           private readonly SchoolContext _context;
    
           public StudentRepository(SchoolContext context)
           {
               _context = context;
           }
    
           public IEnumerable<Student> GetIEnumerableStudents()
           {
               return _context.Students;
           }
    
           public IQueryable<Student> GetIQueryableStudents()
           {
               return _context.Students;
           }
    }

    在Controller中分别调用, 从Repository中返回的数据中,取2条显示在页面上。

    public class HomeController : Controller
    {
           private readonly IStudentRepository _studentRepository;
           public HomeController(IStudentRepository studentRepository)
           {
               _studentRepository = studentRepository;
           }
    
           public ActionResult Index()
           {
               //Repository使用IEnumerable返回结果
               var students = _studentRepository.GetIEnumerableStudents().Take(2);
               //Repository使用IQueryable返回结果
               //var students = _studentRepository.GetIQueryableStudents().Take(2);
               return View(students);
           }
    }

    呈现的页面如下:

    t2

    但是通过MiniProfiler检测到的结果,使得真相水落石出。

    前面一张是使用IEnumerable返回值的,后面一张是使用IQueryable返回值。

    对比能够发现,使用IQueryable的查询,Take(2)的操作是通过Sql在数据库中完成的。

    试想在数据较多的情况下或者操作比较复杂的情况下,IEnumerable的效率会比IQueryable低很多。

    t1

    t3

    四,总结

    结论应当非常明显,使用IQueryable作为Repository的返回值是我们最终的选择。
    同时对于IQueryable有兴趣,不妨多深入研究。里面涉及的表达式树,是.net中的非常重要的概念。

    下篇讨论,如何使用表达式树来增加Repository代码的灵活性。

  • 相关阅读:
    XML属性
    4.9Java游戏项目练习
    关于JVM结构的学习
    HelloWorld之Struts2
    进程调度
    JVM垃圾回收总结
    学会阅读Java字节码
    关于产品需求文档的各种D
    刘强东学习亚马逊:控制供应链 技术是最大障碍
    JVM内存溢出的方式
  • 原文地址:https://www.cnblogs.com/JustRun1983/p/3261074.html
Copyright © 2020-2023  润新知