在Linq-To实体查询中混合函数谓词和表达式谓词
本文关键字:谓词 函数 表达式 混合 Linq-To 实体 查询 | 更新日期: 2023-09-27 18:21:38
给定一个名为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实体查询:
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<string,Fruit>'不包含"All"和最佳扩展方法重载"System.Linq.Enumerable.All<TSource>(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSSource,bool>)'具有一些无效参数
然而,当外部谓词封装在表达式中时:
Expression<Func<IGrouping<string, Fruit>, bool>> outerPredicate =
group => group.All(fruit => fruit.Edible);
var familiesWithAllEdibleFruits = context
.Fruits
.GroupBy(fruit => fruit.Family)
.Where(outerPredicate);
事情运转正常。
我想更好地理解我在这里看到的行为。外部谓词内部对"All"的调用似乎不允许使用Expression参数。是否可以很容易地将查询与函数和表达式互换组合(如第二个示例中所示),或者这是一个固有的限制?
您将能够管理的最好的方法是在此处使用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
的表达式。你需要一种"打开"表达式的方法。简而言之,这并不容易。与编写常规委托相比,编写表达式需要做更多的工作,因为您需要展开每个表达式的主体并将其内联到外部表达式中。