Try   HackMD

Andy , 2023/05/11

IEnumerable與IQueryable

概述

兩者都是用來執行LINQ的Interface,主要的差別在於查詢的方式與執行的時機。

先定義一個DbContext,以便後續說明,並假設Book資料表中有10筆資料。

var dbContext = new DbContext();

IEnumerable

從資料庫中撈取資料,存至記憶體中,並在記憶體中篩選。

//此時的data,已經將資料載入記憶體當中,記憶體有全部10筆資料。
IEnumerable<Book> Edata = dbContext.Book;

//即使在定義變數時加入了where條件式,記憶體中同樣是載入全部10筆資料
IEnumerable<Book> filterEdata = dbContext.Book.Where(x => x.Id ==1);

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

IQueryable

在IDE中寫好的IQueryable只是"查詢狀態",此時還沒執行資料庫的查詢,因此不會有資料載入記憶體的行為。若指派某些會得到"明確結果"的function,如Count()、ToList()等,此時才會執行SQL查詢指令,取得查詢結果。

以下程式定義的變數都會得到IQueryable物件,實際上不會去執行SQL查詢,而是將查詢轉換成Expresion,並將所有查詢條件存於Provider中。

//此時的data是"查詢狀態",資料還未載入記憶體中。
IQueryable<Book> Qdata = dbContext.Book;

//在定義變數時加入條件式,也不會將"查詢狀態"載入記憶體中。
IQueryable<Book> filterQdata = dbContext.Book.Where(x => x.Id == 1);

以下程式會真的執行SQL查詢,IQueryable介面會將Expression傳遞給Provider,由Provider轉譯成T-SQL後,從DB中取得資料,得到"明確結果"

//下面兩行程式才會執行SQL指令,並將查詢的資料載入記憶體中。
var book = filterData.ToList();
var book = filterData.Count();

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

如果在宣告變數時不指定資料型態,會預設指定IQueryable物件。

//data的資料型態是IQueryable物件
var data = dbContext.Book;

注意事項

了解原理之後,才能避免浪費效能的寫法。

由於IEnymerable與IQueryable都有延遲載入的機制,因此使用之前應該先將查詢結果保存,以避免重新查詢。

以下程式是不良示範,每跑一次迴圈都會訪問一次資料庫,如果查詢結果資料量大,就會造成效能降低的負面影響。

IEnumerable<Book> query = dbContext.Book;
 
foreach(var item in query)
{
	var book name = query.Where(x => x.Price < 300);
  //do 
}

存成List就可以避免這個問題。

List<Book> query = dbContext.Book.ToList();

foreach(var item in query)
{
	var book name = query.Where(x => x.Price < 300);
  //do 
}

tags: back-end