2011-06-21 26 views
2

我試圖建立一個通用的方法,EF4.1在數據庫和本地內存中查找表中與特定條件相匹配的特定行。如何使一個匿名方法在LINQ to Entities中運行?

到目前爲止,這就是我所擁有的。

這是來電者。

dbEntities.MyTables.LocalAndDb(delegate(MyTable s) 
       { return s.Description.Contains("test"); }); 

這是LocalAndDb

public static object LocalAndDb<T>(this DbSet<T> myTable, Func<T, bool> function) where T : class 
{ 
    // look in local 
    var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault() 
    // if not exist, look in the database 
    if (item == null) 
    { 
     Expression<Func<T, bool>> predicate = (u) => function(u); 
     item = myTable.Where(predicate).FirstOrDefault(); 
    } 
    return item; 
} 

問題是這條線。

item = myTable.Where(predicate).FirstOrDefault(); 

當它調用數據庫時,它會引發此錯誤。

「LINQ to Entities不支持LINQ表達式節點類型'Invoke'。」

我想這是因爲我傳入一個匿名方法,它不知道如何將其轉換爲SQL。我認爲將其轉換爲表達式對象會做到這一點,但它仍然不適合我。

我需要做什麼才能使匿名方法成爲LINQ可以變成SQL的東西?

回答

4

爲了使這項工作,你需要lambda表達式傳遞給LocalAndDb作爲表達式樹(因此LINQ到實體可以分析代碼,並將其轉換爲SQL):

public static object LocalAndDb<T>(this DbSet<T> myTable, 
    Expression<Func<T, bool>> expr) where T : class { 
    // ... 
    if (item == null) { 
     item = myTable.Where(expr).FirstOrDefault(); 
    } 
    return item; 
} 

然後,當然,問題是在檢查內存數據時你不能執行表達式樹。解決這個問題的一種方法是使用Expression<T>Compile方法,但這會有點低效(取決於您的方案)。

另一種選擇是隻通過條件既功能和表達式樹:

public static object LocalAndDb<T>(this DbSet<T> myTable, 
    Func<T, boo> function, Expression<Func<T, bool>> expr) where T : class { 
    var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault(); 
    if (item == null) { 
     item = myTable.Where(expr).FirstOrDefault(); 
    } 
    return item; 
} 

table.LocalAndDb(t => t.Foo > 10, t => t.Foo > 10); 

這是有點難看,但它並不需要在運行時效率低下編譯。如果你想要一個稍微複雜的解決方案,那麼你可以定義你自己的類型來保持預編譯功能:

class Precompiled<T1, T2> { 
    public Precompiled(Expression<Func<T1, T2>> expr) { 
    this.Expression = expr; 
    this.Function = expr.Compile(); 
    } 
    public Expression<Func<T1,T2>> Expression { get; private set; } 
    public Func<T1,T2> Function { get; private set; } 
} 
+0

編譯工作!謝謝謝謝謝謝!當談到EF時,我是一個全新的新手。但我現在要對性能方面進行一些研究。從你所說的話看來,當你「編譯」表達式時,無論是在方法中,還是在簽名或預編譯構造函數中,這都會影響性能? – Diskdrive

+0

@stickman - 「預編譯」類的想法是,您可以輕鬆構建它一次(調用「編譯」一次),然後在多次調用「LocalAndDb」中重複使用結果,以使表達式爲' t在每次通話期間重新編譯。 –

+0

這很整齊。再次感謝! – Diskdrive