日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Entity Framework中IQueryable, IEnumerable, IList的区别

發(fā)布時間:2025/7/25 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Entity Framework中IQueryable, IEnumerable, IList的区别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

使用工具追蹤EF生成的SQL

使用Entity Framework等ORM框架的時候,SQL對于使用者來說是透明的,往往很多人也不關(guān)心ORM所生成的SQL,然而系統(tǒng)出現(xiàn)性能問題的時候就必須關(guān)注生成的SQL以發(fā)現(xiàn)問題所在。

使用過Toplink的朋友知道很只要設(shè)置日志打印級別=FINE就可以配置使之生成的SQL在服務(wù)器中打印出來,Entiry Framework沒有那么幸運,在以前要檢測生成SQL的唯一方法是SQL Server Profiler,但使用起來并不方便,結(jié)果也不能自動保存到文件中。

Tracing and Caching Provider Wrappers for Entity Framework是Entity Framework Team新推出的開源SQL追蹤和二級緩存的解決方案。原理是在負責執(zhí)行具體SQL語句的data provider(SqlClient或者其他Client)之上插入了一層WrappingProvider,用于監(jiān)控DbCommand.ExecuteReader(), ExecuteScalar() and ExecuteNonQuery(),將Sql命令輸出到指定介質(zhì)或者將查詢結(jié)果緩存起來以重用。

使用方法很簡單,下載源代碼編譯后將dll添加到項目中,新加一個類WrappedNorthWindEntities繼承原有的Entities即可,詳見源代碼中的示例。

測試IQueryable, IEnumerable, IList的區(qū)別

下面我們使用EF Wrapper來監(jiān)測Entify Framework中IQueryable, IEnumerable和IList所生成的SQL。

TestIQueryable private static void TestIQueryable()
{
using (var ctx = new WrappedNorthWindEntities())
{
IQueryable<Product> expression = ctx.Products.Take(5);
IQueryable<Product> products = expression.Take(2); // A 不執(zhí)行SQL
Console.WriteLine(products.Count());          // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
Console.WriteLine(products.Count());          // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
foreach (Product p in products)             // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products)             // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )
{
Console.WriteLine(p.ProductName);
}
}
} 復制代碼

?

TestIEnumerable private static void TestIEnumerable()
{
using (var ctx = new WrappedNorthWindEntities())
{
IEnumerable<Product> expression = ctx.Products.Take(5).AsEnumerable();
IEnumerable<Product> products = expression.Take(2); // A 不執(zhí)行SQL
Console.WriteLine(products.Count());          // B SELECT TOP (5) * FROM [dbo].[Products]
Console.WriteLine(products.Count());          // C SELECT TOP (5) * FROM [dbo].[Products]
foreach (Product p in products)             // D SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products)             // E SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
}
} 復制代碼

?

TestIList private static void TestIList()
{
using (var ctx = new WrappedNorthWindEntities())
{
var expression = ctx.Products.Take(5);
IList<Product> products = expression.Take(2).ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]

Console.WriteLine(products.Count());           // B 不執(zhí)行SQL
Console.WriteLine(products.Count());           // C 不執(zhí)行SQL
foreach (Product p in products)              // D 不執(zhí)行SQL
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products)             // E 不執(zhí)行SQL
{
Console.WriteLine(p.ProductName);
}
}
} 復制代碼

測試結(jié)果

  • IQueryable和IEnumerable都是延時執(zhí)行(Deferred Execution)的,而IList是即時執(zhí)行(Eager Execution)
  • IQueryable和IEnumerable在每次執(zhí)行時都必須連接數(shù)據(jù)庫讀取,而IList讀取一次后,以后各次都不需連接數(shù)據(jù)庫。前兩者很容易造成重復讀取,性能低下,并且可能引發(fā)數(shù)據(jù)不一致性
  • IQueryable和IEnumerable的區(qū)別:IEnumberalb使用的是LINQ to Object方式,它會將AsEnumerable()時對應(yīng)的所有記錄都先加載到內(nèi)存,然后在此基礎(chǔ)上再執(zhí)行后來的Query。所以上述TestIEnumerable例子中執(zhí)行的SQL是"select top(5) ...",然后在內(nèi)存中選擇前兩條記錄返回。
  • 以下是一個IQueryable引發(fā)數(shù)據(jù)不一致性的例子:記錄總數(shù)和記錄詳情兩者本應(yīng)一致,但由于IQueryable前后兩次讀取數(shù)據(jù)庫,結(jié)果是現(xiàn)實有10條記錄,卻輸出11條詳情。

    IQueryable Data Inconsistancy IQueryable<Product> expression = ctx.Products.All();
    //開始的時候數(shù)據(jù)庫product表中有10條記錄, count = 10
    int count = products.Count();
    Console.WriteLine("Count of products:"+count);
    //此時另一進程添加一個產(chǎn)品進數(shù)據(jù)庫 //會重新讀取數(shù)據(jù)庫并輸出11個產(chǎn)品名稱
    foreach (Product p in products)
    {
    Console.WriteLine(p.ProductName);
    } 復制代碼

    結(jié)論

    基于性能和數(shù)據(jù)一致性這兩點,我們使用IQueryable時必須謹慎,而在大多數(shù)情況下我們應(yīng)使用IList

    • 當你打算馬上使用查詢后的結(jié)果(比如循環(huán)作邏輯處理或者填充到一個table/grid中),并且你不介意該查詢會即時執(zhí)行,使用ToList()
    • 當你希望查詢后的結(jié)果可以供調(diào)用者(Consummer)作后續(xù)查詢(比如這是一個"GetAll"的方法),或者你希望該查詢延時執(zhí)行,使用AsQueryable()

    轉(zhuǎn)載于:https://www.cnblogs.com/westernsky/archive/2011/12/22/2297354.html

    總結(jié)

    以上是生活随笔為你收集整理的Entity Framework中IQueryable, IEnumerable, IList的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。