zoukankan      html  css  js  c++  java
  • 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代码的灵活性。

     
  • 相关阅读:
    网络安全分析
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1540 机器
    java实现 洛谷 P1540 机器
  • 原文地址:https://www.cnblogs.com/webenh/p/7691732.html
Copyright © 2011-2022 走看看