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代碼的靈活性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM