2014-09-12 3 views
1

Учитывая объект, называемый фрукты:Смешивание Func и Expression Предикаты в Linq Для Entity запросов

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 < строки, фрукты>» не содержит определение для «Все» и лучшей перегрузки системы метода расширения». Linq.Enumerable.All < TSource> (System.Collections.Generic.IEnumerable < TSource>, System.Func < TSource, BOOL>)»имеет некоторые недопустимые аргументы

Но когда внешний предикат заключен в выражение:

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

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

все работает правильно.

Я хотел бы понять поведение, которое я вижу здесь лучше. Похоже, что вызов «Все» внутри внешнего предиката не позволит использовать параметры выражения. Можно ли легко составлять запросы взаимозаменяемо с помощью Funcs и выражений (как во втором примере), или это неотъемлемое ограничение?

+0

Этот вопрос может быть связан с http://stackoverflow.com/questions/19930389/expression-tree-with-linq-expressions – rtev

ответ

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. Вам нужен способ «разворачивания» выражения. Короче говоря, это просто непросто. Для составления выражений требуется гораздо больше работы, чем для составления регулярных делегатов, так как вам нужно развернуть тело каждого выражения и вложить его в внешнее выражение.

Смежные вопросы