IEnumerable vs IQueryable - 差異

  • 7253
  • 0
  • 2017-12-19

在.NET使用 Linq 的情況,通常都會用到 Linq to Object、 Linq to Sql、Linq to EF 這幾種方式,但在使用上『宣告變數』或是『方法參數』上的 "不同" 會產生『完全不同的結果』。以下自己做個紀錄。

 

參考網站 


 

在這裡都假設是用 Entity Framework 當資料來源。

 

IEnumerable

var db = new MyDbContext();
// 這個時候 Linq to Object 還未取得資料(延遲查詢)
IEnumerable<TEntity> data = db.TEntity; 
// 這裡是重點 !! 從資料庫伺服器取得所有資料後才做篩選
//// Where中的參數為 Lamdba運算式,是使用 Func<> 的方式傳遞
////// 也就是委派方法用函數的方式表示
IEnumerable<TEntity> filterData = db.TEntity.Where(x => x.id == 2); 
以上的程式碼(針對最後一行)的示意圖 : 

使用IEnumerable會將資料庫端的資料一次取回到記憶體後,再從記憶體做篩選的動作 !!!

 

IQueryable

var db = new MyDbContext();
 // 這個時候 Linq to EF 還未取得資料(延遲查詢)
IQueryable<TEntity> data = db.TEntity;
 // 這裡是重點 !! 請求資料庫伺服器作篩選的動作且回傳結果
 //// Where中的參數為 表達示,是使用 Expression<Func<> >的方式傳遞
 ////// 也就是使用 表達示樹 來陳述這個 Lamdba運算式 的資料結構(IL)來表達
IQueryable<TEntity> filterData = db.TEntity.Where(x => x.id == 2);
 以上的程式碼(針對最後一行)的示意圖 : 

使用IQueryable會請求資料庫伺服器做篩選後再回傳結果 !!!

 

IEnumerable  &&  IQueryable  延遲查詢

IEnumerable && IQueryable  搭配 Linq 都會使用延遲查詢的機制,做 .Where()、.Count()、Any()...等事情都會再『重新查詢』,若不需要重新查詢這個效果的話應先把查詢結果轉成.NET中的集合物件。

EX :  

var db = new MyDbContext();
IEnumerable data = db.PdMast.Where(x=>x.ID==1); // 查詢 id==1
IQueryable queryData = db.PdMast.Where(x=>x.ID==1); // 查詢 id==1
 此時做Linq的擴充方法時,都將會再一次重新查詢,也就是說要再跑一次db.PdMast.Where(x=>x.ID==1) !!!
 
// 將查詢結果保存起來
var dataList = data.ToList();
var queryDataList = query.ToList();

做了這個動作,之後在做任何動作時都不會在觸發重新查詢 !!

var count = dataList.Count();
var count2 = queryDataList.Count();
....

 

 

IEnumerable && IQueryable 使用 Linq 擴充方法之差異

參數型別的不同 :

  • IEnumerable 的參數版本 : .Where(Func<TEntity,bool> predicate)
  • IQueryable    的參數版本 : .Where(Expression<Func<TEntity,bool>> predicate)
因為在使用的『語法』上的相同,可能會讓我們忽略了『參數型別』上是不同的!!
EX :
db.PdMast.Where(x=>x.ID==1); // <<= 這段語法都適用於 IEnumerable 或 IQueryable

編譯結果 :  

  • IEnumerable : 使用函數的方式陳述
  • IQueryable    : 使用表達示樹(Tree)的方式陳述。這種方法對於 To Sql..等效能上是較佳的 !!

 


多多指教!! 歡迎交流!!

你不知道自己不知道,那你會以為你知道