在.NET使用 Linq 的情況,通常都會用到 Linq to Object、 Linq to Sql、Linq to EF 這幾種方式,但在使用上『宣告變數』或是『方法參數』上的 "不同" 會產生『完全不同的結果』。以下自己做個紀錄。
參考網站
- https://www.codeproject.com/Articles/766541/IEnumerable-vs-IQueryable
- https://gxnotes.com/article/28844.html
- https://gxnotes.com/article/14272.html
- http://www.huanlintalk.com/2016/07/learning-linq-1.html
- http://www.huanlintalk.com/2016/07/learning-linq-2.html
- https://dotblogs.com.tw/asdtey/Tags/Linq%20to%20Entities/default.aspx
- http://jasper-it.blogspot.tw/2015/01/c-ienumerable-ienumerator.html
在這裡都假設是用 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
EX :
db.PdMast.Where(x=>x.ID==1); // <<= 這段語法都適用於 IEnumerable 或 IQueryable
編譯結果 :
- IEnumerable : 使用函數的方式陳述
- IQueryable : 使用表達示樹(Tree)的方式陳述。這種方法對於 To Sql..等效能上是較佳的 !!
多多指教!! 歡迎交流!!
你不知道自己不知道,那你會以為你知道