コードから次の例を簡略化し、それが原因で明らかなコンパイルエラーが発生しないことを期待しています。次のエンティティがあるとしましょう(実際に持っているものではありません。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'
グループ化すると、「それ」はどのタイプですか? IGrouping<string, Company>
またはIQueryable<Company>
であると想定する他の式を使用してみましたが、同じエラーが発生します。 "Cost"を選択し、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.
したがって、この動的なグループ化と独自の選択式の挿入により、「それ」のデータ型は何であると想定する必要がありますか?これでも機能しますか?
タイプit
であるIGrouping<TKey, TElement>
TKey
に基づいて、動的であるkeySelector
結果のタイプ、及びTElement
入力の要素型であるIQueryable
。幸いにも、 IGrouping<TKey, TElement>
はIEnumerable<TElement>
IGrouping<TKey, TElement>
継承しているため、入力要素の型がわかったらすぐに、セレクターをIEnumerable<TElement>
基づいて安全に作成できます。
つまり、 Expression<Func<IEnumerable<Company>, decimal?>>
基づく最後の試行は正しいです。
@0(it)
がEFでサポートされていないExpression.Invoke
呼び出しを生成するため、新しいエラーが発生しています。これを修正する最も簡単な方法は、 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;