Передача агрегатного выражения выбора в GroupBy Dynamic Linq - PullRequest
0 голосов
/ 22 мая 2018

Я упростил следующий пример из своего кода и надеюсь, что из-за этого нет очевидных ошибок компиляции.Допустим, у меня есть следующие объекты (не то, что у меня есть на самом деле, пожалуйста, предположим, у меня нет проблем с EF или схемой, это только для примера):

public class Company
{
  public string GroupProperty {get;set;}
  public virtual ICollection<PricingForm> PricingForms {get;set;}
}
public class PricingForm
{
  public decimal Cost {get;set;}
}

И я хочу сделать запрос вот так:

IQueryable DynamicGrouping<T>(IQueryable<T> query)
{
  Expression<Func<Company, decimal?>> exp = c => c.PricingForms.Sum(fr => fr.Cost);
  string selector = "new (it.Key as Key, @0(it) as Value)";
  IQueryable grouping = query.GroupBy("it.GroupProperty", "it").Select(selector, exp);
  return grouping;
}

Я получаю следующую ошибку при вызове строки groupby / select:

System.Linq.Dynamic.ParseException: 'Argument list incompatible with lambda expression'

Какой тип "it" при группировке?Я пытался использовать другие выражения, которые предполагают, что это IGrouping<string, Company>, или IQueryable<Company>, та же ошибка.Я попытался просто выбрать «Стоимость» и переместить агрегат Sum () в строку селектора (т. Е. Sum(@0(it)) as Value) и, похоже, всегда получаю одну и ту же ошибку.

В конце концов я попробовал что-то вроде

Expression<Func<IEnumerable<Company>, decimal?>> exp = l => l.SelectMany(c => c.PricingForms).Sum(fr => fr.Cost);

Однако, этот я получаю дальше, но, пытаясь перебрать результаты, я получил другую ошибку.

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.

Итак, с этой динамической группировкой и введением моего собственного выборавыражение, что я должен предполагать тип данных «это»?Будет ли это даже работать?

1 Ответ

0 голосов
/ 23 мая 2018

Тип it равен IGrouping<TKey, TElement>, где TKey является динамическим в зависимости от типа результата keySelector, а TElement является типом элемента ввода IQueryable.К счастью IGrouping<TKey, TElement> наследует (является) IEnumerable<TElement>, поэтому, как только вы узнаете тип входного элемента, вы можете смело основывать селектор на IEnumerable<TElement>.

Другими словами, последняя попытка основана на Expression<Func<IEnumerable<Company>, decimal?>> является правильным.

Новая ошибка, которую вы получаете, потому что @0(it) генерирует Expression.Invoke вызов, который не поддерживается EF.Самый простой способ исправить это, используя LINQKit Expand метод:

Expression<Func<Company, decimal?>> exp = c => c.PricingForms.Sum(fr => fr.Cost);
string selector = "new (it.Key as Key, @0(it) as Value)";
IQueryable grouping = query.GroupBy("it.GroupProperty", "it").Select(selector, exp);

// This would fix the EF invocation expression error
grouping = grouping.Provider.CreateQuery(grouping.Expression.Expand());

return grouping;
...