2014-09-12 54 views
1

鑑於所涉及的實體,稱爲水果:混合FUNC鍵,表達謂詞在LINQ to實體的查詢

public class Fruit 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Family { get; set; } 
    public bool Edible { get; set; } 
} 

以下LINQ到實體查詢:

var familiesWithAllEdibleFruits = context 
    .Fruits 
    .GroupBy(fruit => fruit.Family) 
    .Where(group => group.All(fruit => fruit.Edible)); 

生成單個SQL語句選擇正確的記錄:

SELECT 
    [Project4].[C1] AS [C1], 
    [Project4].[Family] AS [Family], 
    [Project4].[C2] AS [C2], 
    [Project4].[Id] AS [Id], 
    [Project4].[Name] AS [Name], 
    [Project4].[Family1] AS [Family1], 
    [Project4].[Edible] AS [Edible] 
    FROM (SELECT 
     [Project2].[Family] AS [Family], 
     [Project2].[C1] AS [C1], 
     [Project2].[Id] AS [Id], 
     [Project2].[Name] AS [Name], 
     [Project2].[Family1] AS [Family1], 
     [Project2].[Edible] AS [Edible], 
     CASE WHEN ([Project2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] 
     FROM (SELECT 
      [Distinct1].[Family] AS [Family], 
      1 AS [C1], 
      [Extent2].[Id] AS [Id], 
      [Extent2].[Name] AS [Name], 
      [Extent2].[Family] AS [Family1], 
      [Extent2].[Edible] AS [Edible] 
      FROM (SELECT DISTINCT 
       [Extent1].[Family] AS [Family] 
       FROM [dbo].[Fruits] AS [Extent1]) AS [Distinct1] 
      LEFT OUTER JOIN [dbo].[Fruits] AS [Extent2] ON ([Distinct1].[Family] = [Extent2].[Family]) OR (([Distinct1].[Family] IS NULL) AND ([Extent2].[Family] IS NULL)) 
     ) AS [Project2] 
     WHERE NOT EXISTS (SELECT 
      1 AS [C1] 
      FROM [dbo].[Fruits] AS [Extent3] 
      WHERE (([Project2].[Family] = [Extent3].[Family]) OR (([Project2].[Family] IS NULL) AND ([Extent3].[Family] IS NULL))) AND ([Extent3].[Edible] <> cast(1 as bit)) 
     ) 
    ) AS [Project4] 
    ORDER BY [Project4].[Family] ASC, [Project4].[C2] ASC 

但是下面的代碼裏面的謂詞是一個表達式:

Expression<Func<Fruit, bool>> innerPredicate = fruit => fruit.Edible; 

var familiesWithAllEdibleFruits = context 
    .Fruits 
    .GroupBy(fruit => fruit.Family) 
    .Where(group => group.All(innerPredicate)); 

卡在編譯器的嗉囊:

「System.Linq.IGrouping <串,水果>」不包含「所有」的定義和最佳推廣方法重載「系統。 Linq.Enumerable.All < TSource>(System.Collections.Generic.IEnumerable < TSource>,System.Func < TSource,布爾>)」具有一些無效參數

然而當外謂詞是封裝在一個表達式中:

Expression<Func<IGrouping<string, Fruit>, bool>> outerPredicate = 
    group => group.All(fruit => fruit.Edible); 

var familiesWithAllEdibleFruits = context 
    .Fruits 
    .GroupBy(fruit => fruit.Family) 
    .Where(outerPredicate); 

事情工作正常。

我想了解我在這裏看到的更好的行爲。它看起來像在外部謂詞內對「全部」的調用將不允許表達式參數。是否可以使用Funcs和Expressions(如第二個例子)一樣方便地構成查詢,或者這是一個固有的限制嗎?

+0

此問題可能與http://stackoverflow.com/questions/19930389/expression-tree-with-linq-expressions有關 – rtev 2014-09-12 20:24:44

回答

1

,你將能夠管理的最佳方法是使用LINQKit這裏:

Expression<Func<Fruit, bool>> innerPredicate = fruit => fruit.Edible; 

var familiesWithAllEdibleFruits = context 
    .Fruits 
    .GroupBy(fruit => fruit.Family) 
    .Where(group => group.All(fruit => innerPredicate.Invoke(fruit))) 
    .Expand(); 

至於爲什麼,你的第一個代碼段中是代表表示Func的表達的表達,而你想要的只是一個表示Func的表達式。你需要一種「解開」表達的方式。總之,這並不容易。編寫表達式比編寫常規代表花費更多的工作,因爲您需要解開每個表達式的主體並將其內聯到外部表達式中。