2012-07-23 107 views
2

我有一個泛型類型過濾器,它需要一些lambda表達式來從類型中選擇值以便該類可重用。該類用於另一個泛型類Search中,它將使用Filter來選擇最終將在下拉列表中使用的不同類型的項目。在linq select語句中用func選擇匿名類型的值

我刪除了這些不重要的代碼。

public class Filter<T> 
{ 
    public string Name; 
    public Func<T, string> Key; 
    public Func<T, string> Value; 
} 

public class Search<T> 
{ 
    MyDBContext db = new MyDBContext(); 
    IQueryable<T> Model = db.Stuff.OrderBy(a => a.TermID); 
    Filter filter = new Filter(
     Name: "Term", 
     Value: a => a.TermID.ToString(), 
     Key: a => a.Term.TermType.Name 
    ); 

    var filterItems = Model 
     .Select(a => new { Key = filter.Key(a), Value = filter.Value(a)}) 
     .OrderBy(t => t.Key) 
     .Distinct() 
     .ToArray(); 
} 

我得到的運行時錯誤:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 我一直在使用強類型而不是匿名類型,並在過濾器使用Expression<Func<T,string>>嘗試。

經過數小時的搜索和嘗試不同的事情,我不知道如何使這項工作。 謝謝你的幫助。

+0

我懷疑無論'filter.Key'和'filter.Value'是否可以從LINQ轉換到您的後端存儲。 – mellamokb 2012-07-23 21:51:49

+1

如果Invoke是主要問題,那麼可以通過使用ExpressionVisitor來融合這兩個表達式來避免。我不在PC上,但如果你沒有得到任何喜悅,請提醒我,我會添加一個例子。 – 2012-07-23 22:14:41

回答

0

你的問題可以表述更加簡單,比如,這也再現:

Func<SomeClass, int> x = t => t.ID; 
var y = db.SomeClasses.Select(c => x(c)).ToArray(); 

它編譯罰款,但在運行時給出了同樣的錯誤,因爲你調用編譯功能。該部分「t => t.ID」是編碼(至少是IL),linq無法讀取它將其轉換爲SQL。它只能將表達式樹轉換爲SQL。上述案例的解決方案相當簡單,我不確定這將如何轉化爲您的情況,但應該可以。

Expression<Func<SomeClass, int>> x = t => t.ID; 
var y = db.SomeClasses.Select(x).ToArray(); 

還有的移動函數調用到的LINQ to對象,所以它並不需要被轉換爲SQL(後一切「AsEnumerable」在客戶端上處理)的選項。這樣可以在功能中放置更多的靈活性,並消除您獲得的錯誤類型。這也將消除調用SqlFunctions的需要(見下文)。缺點是可能會返回比從服務器需要更多的行。

Func<SomeClass, int> x = t => t.ID; 
var y = db.SomeClasses.AsEnumerable().Select(c => x(c)).ToArray(); 

你的最後一個問題是,EF不喜歡ToString方法,你將需要使用SqlFunctions.StringConvert這是相當糟糕的。看到這裏:int to string in Entity Framework

+0

謝謝。我現在正在閱讀更多關於這個東西的內容。 – Kyle 2012-07-24 17:44:50