2016-04-18 10 views
1

私は、パラメータが式((Expression<Func<CompanyModel,TKey>> myGroupingProperty)によってパラメータ化可能で、もう1つがハードコードされているグループでLinQリクエストを実行しようとしています。しかし、私のコードをコンパイルしても、linqがlambdaをサポートしていないというエラーが出ます。この要求をどうやって行うか考えていますか?ここでLinqの2つのプロパティでパラメータ化可能なグループ

は、コードサンプルです:

public List<timelineResult> getTimelinebyCompany<TKey>(Expression<Func<CompanyModel,TKey>> myGroupingProperty, Filter item) 
{ 
    int cntToBeSureThatTheQueryExecuteAtLeastOneTime = 0; 
    List<timelineResult> toto = new List<timelineResult>(); 
    using (var db = new fintechDbContext()) 
    {   
     while (cntToBeSureThatTheQueryExecuteAtLeastOneTime == 0) 
     { 
      toto = (from p in db.companyDBSET          
        select p).GroupBy(p=> new {p.Founded_Year, myGroupingProperty}) 
          .Select(o => new timelineResult{ year = o.Key.Founded_Year, cluster = o.myGroupingProperty.ToString(), count = o.Count() }) 
          .OrderBy(o => o.year).ToList(); 
      cntToBeSureThatTheQueryExecuteAtLeastOneTime++; 
     } 
    } 

    return toto; 
} 
+0

*正確に*エラーメッセージは何ですか? –

+0

単なるスニペットではなく[mcve]を提供することも役立ちます。 –

+0

これはうまくいきません。ラムダで使用しています。ネストされたラムダを使って 'p => new {p.Founded_Year、p2 => p2.PropertyToGroupBy}'のようなことをしようとしています。おそらく、これを行うには式ツリーを使用するか、キーの一部だけではなく、完全な 'p => new {p.Founded_Year、myGroupingProperty}'をパラメータとして提供する必要があります(クラス/キーの匿名型で作業する必要があります)。 –

答えて

2

何を求めていることは渡されたラムダ式は、別のラムダ式内で直接使用することはできませんので、あなたがしようとした方法でなんとかですが、ありません。

まず、グループ化キーを保持する汎用クラスを作成します。それはTupleを提供するシステムと同様ですが、パラメータなしのコンストラクタと、単純なプロパティを取得/セッターはEF投影規則に準拠しています

public class GroupKey<K1, K2> 
{ 
    public K1 Key1 { get; set; } 
    public K2 Key2 { get; set; } 
} 

次にあなたがこの

Expression<Func<T, K1, K2>> keySelector = x => 
    new GroupKey<K1, K2> { Key1 = x.Prop1, Key2 = x.Prop2 }; 

のような動的にラムダ式を作成する必要があります

public static class ExpressionUtils 
{ 
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target) 
    { 
     return new ParameterReplacer { Source = source, Target = target }.Visit(expression); 
    } 

    class ParameterReplacer : ExpressionVisitor 
    { 
     public ParameterExpression Source; 
     public Expression Target; 
     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return node == Source ? Target : base.VisitParameter(node); 
     } 
    } 
} 

、あなたが交流でグループ化部分をカプセル化することができます:あなたは、いくつかの Expressionヘルパーをする必要があります、それを行うためにustom拡張メソッドは:

public static class QueryableExtensions 
{ 
    public static IQueryable<IGrouping<GroupKey<K1, K2>, T>> GroupByPair<T, K1, K2>(this IQueryable<T> source, Expression<Func<T, K1>> keySelector1, Expression<Func<T, K2>> keySelector2) 
    { 
     var parameter = keySelector1.Parameters[0]; 
     var key1 = keySelector1.Body; 
     var key2 = keySelector2.Body.ReplaceParameter(keySelector2.Parameters[0], parameter); 
     var keyType = typeof(GroupKey<K1, K2>); 
     var keySelector = Expression.Lambda<Func<T, GroupKey<K1, K2>>>(
      Expression.MemberInit(
       Expression.New(keyType), 
       Expression.Bind(keyType.GetProperty("Key1"), key1), 
       Expression.Bind(keyType.GetProperty("Key2"), key2)), 
      parameter); 
     return source.GroupBy(keySelector); 
    } 
} 

最後に、あなたの方法の重要な部分はこのようになった:

toto = db.companyDBSET          
    .GroupByPair(p => p.Founded_Year, myGroupingProperty) 
    .Select(g => new timelineResult 
    { 
     year = g.Key.Key1, 
     cluster = g.Key.Key2.ToString(), 
     count = g.Count() 
    }) 
    .OrderBy(o => o.year) 
    .ToList(); 
関連する問題