2010-08-22 64 views
3

我正在開發一個使用EF 4.0和POCO的小型應用程序。EF 4.0/FirstOrDefault方法的奇怪行爲

在測試我的應用程序時,我越來越擔心數據訪問層的性能。所以我解僱SQL事件探查器查看,試圖檢索記錄時:

ctx.Orders.Include("OrderItems").FirstOrDefault<Order>(c => c.OrderID == id); 

的EF發出,將在服務器上檢索和此時L2E這種迴歸DAL Orders表中所有記錄的SQL語句會選擇符合標準的人並將其退回。

可以更改此行爲。

謝謝!

回答

9

試試這個請:

ctx.Orders.Include("OrderItems").Where(c => c.OrderID == id).FirstOrDefault(); 


通過你不需要尋找到SQL事件探查器查看生成的SQL的方式,你可以這樣做是正確的內部你的代碼通過寫

IQueryable<Order> query = ctx.Orders.Include("OrderItems") 
            .Where(c => c.OrderID == id); 
string sql = ((ObjectQuery<Order>)query).ToTraceString(); 


編輯:
問:如果我們有像FindOrders的功能,我們需要的謂詞傳遞給這個功能呢? 答:代碼應該是這樣的:

public List<Order> FindOrders(Expression<Func<Order, bool>> predicate) { 
    using (DBContext ctx = new DBContext()) { 
     return ctx.Orders.Include("OrderItems").Where(predicate).ToList<Order>(); 
    } 
} 

//Calling the function: 
var order = FindOrders(c => c.OrderID == id)[0]; 


這個時候,如果你檢查你的SQL事件探查器,你會看到有一個地方在一個已經提交給SQL Server中的SQL子句。

說明:
這樣做的原因 「怪異的行爲」 是,基本上當你寫在哪裏(C => c.OrderID == ID),C#編譯器投你的lambda表達式到表達< Func鍵< TSource,int,bool >>而不是Func < TSource,int,bool>。

MSDN Documentation for Queryable.Where也證實了這一點:

 
public static IQueryable<TSource> Where<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, int, bool>> predicate 
) 

但是,如果你明確地傳遞函數求< TSource,INT,BOOL >>給Where方法,那麼你基本上調用 Enumerable.Where:

 
public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, int, bool> predicate 
) 

而因爲我們知道IEnumerable.Where是「LINQ to Objects」的實現,而不是「LINQ to Entities」,這意味着你到達IEnumerable.Where調用的主體,ObjectQuery運行初始曲線(ctx.Orders.Include(「OrderItems」))並將結果提供給IEnumerable.Where,以便它將在 客戶端上爲您篩選出來。另一方面,Queryable.Where(ctx.Orders.Include(「OrderItems」)。其中(c => c.OrderID == id).FirstOrDefault())的調用在它到達之前不會被執行直到我們調用FirstOrDefault()函數,這意味着Queryable.Where隨後會與查詢的其餘部分一起轉換爲本機SQL,並將傳遞給SQL Server,因此您會看到SQL語句中的Where子句是所需的運行時行爲。

順便說一句,不要忘了這個命名空間導入類文件:
 
using System.Linq.Expressions; 

+0

感謝莫爾塔扎您的及時回覆。這可以工作。儘管如此,我應該以不同的方式表達我的問題我有一個函數如下: 公開名單 FindOrders(Func鍵謂語) \t \t { \t \t \t使用(CTX的DbContext =新的DbContext()) \t \t \t { \t \t \t \t回報ctx.Orders 。(包括(「OrderItems」)。Where(predicate).ToList (); \t \t \t} \t \t} 當調用此函數等變種順序= rep.FindOrders(C => c.OrderID == ID)[0]比SQL探查表明不包含SELECT語句一個WHERE子句。 任何想法? 再次感謝! Zen – UncleZen 2010-08-22 14:19:28

+0

沒問題。我已經編輯了我的答案,將謂詞傳遞給一個函數來解決這個問題。請看看,讓我知道這個如何適合你。 – 2010-08-23 00:18:13

+0

感謝Morteza,您的詳細解答。我等不及要回家時試試這個。我會及時通知你的。 Zen – UncleZen 2010-08-23 13:01:08