在Linq To Entity查询中混合Func和表达式谓词

时间:2014-09-12 19:22:02

标签: c# entity-framework linq-to-entities

给定一个名为Fruit的实体:

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

以下Linq-To-Entities查询:

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&LT; string,Fruit&gt;'不包含'All'的定义和最佳扩展方法重载'System.Linq.Enumerable.All&lt; TSource&gt;(System.Collections.Generic.IEnumerable&lt; TSource&gt;,System.Func&lt; TSource,bool&gt;)'有一些无效的参数

然而,当外部谓词被封装在表达式中时:

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交换组合查询(如第二个例子)或这是一个固有的限制?

1 个答案:

答案 0 :(得分: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。你需要一种方式解开&#34;表达方式。简而言之,这根本不容易。组合表达式比组成常规委托需要花费更多的工作,因为你需要解开每个表达式的主体并将其内联到外部表达式中。