2013-09-27 106 views
6

我想寫一個LINQ實體擴展方法,它需要一個Func來選擇一個屬性ID並將其與ID列表進行比較。如何在Linq to Entity Framework的表達式中使用Func?

public class A 
{ 
    public int AId { get; set; } 
} 

public class B 
{ 
    public int BId { get; set; } 
} 

擴展方法

public static IQueryable<T> WithId<T>(this IQueryable<T> entities, 
    Func<T, int> selector, IList<int> ids) 
    { 
     Expression<Func<T, bool>> expression = x => ids.Contains(selector(x)); 
     return entities.Where(expression); // error here (when evaluated) 
    } 

調用方法

var ids = new List<int> { 1, 2, 3 }; 
DbContext.EntityAs.WithId(e => e.AId, ids); 
DbContext.EntityBs.WithId(e => e.BId, ids); 

我的問題體驗是它試圖調用實體框架中不允許的功能。

如何使用屬性選擇器(Func)來評估查詢?

+0

您可以在EF查詢中調用的代碼範圍受限於它仍然需要在SQL中進行翻譯的事實。在你的情況下,EF不知道如何自動翻譯IList。 –

+0

我不確定你是否正確。 DbContext.EntityAs.Where(e => ids.Contains(e.Id))由EF正確轉換。我只是想做一個可重用的函數,以便我可以定義要選擇的屬性。 – David

+0

因爲在另一個實體關係的情況下,EF知道如何在可枚舉的情況下選擇x,其中x在(1,2,3)中,或者選擇x,其中x在(選擇y)中。在你的情況下,EF需要編譯類似'select x where x in(select y(where F(y)in(F(1),F(2),...))''。儘管可以手動執行此操作,但EF不支持該情況*尚未* –

回答

15

您必須通過Expression<Func<T, int>>而不是Func<T, int>並自行構建完整的表達式。這將這樣的伎倆:

public static IQueryable<T> WithId<T>(this IQueryable<T> entities, 
    Expression<Func<T, int>> propertySelector, ICollection<int> ids) 
{ 
    var property = 
     (PropertyInfo)((MemberExpression)propertySelector.Body).Member; 

    ParameterExpression parameter = Expression.Parameter(typeof(T)); 

    var expression = Expression.Lambda<Func<T, bool>>(
     Expression.Call(
      Expression.Constant(ids), 
      typeof(ICollection<int>).GetMethod("Contains"), 
      Expression.Property(parameter, property)), 
     parameter); 

    return entities.Where(expression); 
} 

當您嘗試讓你的代碼幹你的O/RM工作時,你會經常與表達式樹撥弄。這裏是another fun example

+0

太棒了。我正在試驗如何從http://blogs.msdn.com/b/miah/archive/2009/02/06/dynamic-expression-trees.aspx和http://stackoverflow.com/questions/構建表達式樹。 820896/listobject-contained-expression-tree但無法弄清楚如何構建Collection/List包含。謝謝! – David

+3

@DavidLiddle:我會告訴你一個小祕密:我只需編寫LINQ查詢,編譯並打開Reflector以查看C#編譯器生成的內容。您也可以在調試器中看到這些信息,但Reflector更容易。 – Steven

+0

您可以舉一個「簡單寫LINQ查詢」的例子。使用ILSpy我只看到我寫的確切的LINQ查詢! – David