3

私は子プロパティでフィルタリングする必要があるリストを持っています。フィルタ演算子は動的で、いくつかのフィルタ/ lambdasを結合するために述語ビルダーを使用しています。簡単にするためにネストされたプロパティを持つ動的linq式ツリー

、のは、私はこのような2つのクラスを持っているとしましょう:

public class FirstClass 
{ 
    public int Id { get; set; } 
    public ICollection<SecondClass> MyList { get; set; } 
} 

public class SecondClass 
{ 
    public int ReferenceId { get; set; } 
    public int Value { get; set; } 
} 

私のフィルタは、擬似コードは次のようになるよう、オペレータのタイプと値を参照IDを使用します。

"list of FirstClass".Where(param1 => 
    param1.MyList.Single(param2 => 
     param2.ReferenceId == "reference id").Value "operatorType" "value") 

実際のフィルタは、参照番号123で、operatorTypeは「EQ」であり、値は456

operat場合である123 eq 456ようなもの、であろうまた、唯一の動的な式とFirstClassにフィルタリング、例えば、魔法のように動作

Expression<Func<FirstClass, bool>> lambda = 
    param1 => param1.MyList.Single(param2 => param2.ReferenceId == id).Value == value; 

:またはちょうどうまく平等、その後、次のような作品でしたIDにフィルタリング(私のExpressionTypeDictionaryが提供operatorTypeに基づいExpressionTypeを選択するための辞書です):

var parameter = Expression.Parameter(typeof(FirstClass), "param1"); 
Expression body = parameter; 
body = Expression.Property(body, "Id"); 
body = Expression.MakeBinary(ExpressionTypeDictionary[operatorType], body, value); 
var lambda = Expression.Lambda<Func<FirstClass, bool>>(body, new[] { parameter }); 

私は次のようにコンパイルするために取得することができるよ、しかし、EFコアを使用して、実際のデータにフィルタを実行すると返されますquerySourceのための例外:任意の提案が高く評価されている

var parameter = Expression.Parameter(typeof(FirstClass), "param1"); 
Expression<Func<FirstClass, int>> left = param1 => 
    param1.MyClass.Single(param2 => param2.ReferenceId == id).Value; 
var body = Expression.MakeBinary(
    ExpressionTypeDictionary[operatorType], 
    left.Body, 
    Expression.Constant(value)); 
var lambda = Expression.Lambda<Func<FirstClass, bool>>(body, new[] { parameter }); 
... 
theList.Where(lambda); 

:)

答えて

4

私はこの

のような表現ではなく、考えます
Expression<Func<FirstClass, bool>> predicate = 
    x => x.MyList.Single(y => y.ReferenceId == id).Value [operator] value; 

方が良い、このように式を構築したい:ここ

Expression<Func<FirstClass, bool>> predicate = 
    x => x.MyList.Any(y => y.ReferenceId == id && y.Value == value); 

は、あなたがそれを行うことができる方法である。

var innerParameter = Expression.Parameter(typeof(SecondClass), "y"); 
var innerPredicate = Expression.Lambda<Func<SecondClass, bool>>(
    Expression.AndAlso(
     Expression.Equal(Expression.Property(innerParameter, "ReferenceId"), Expression.Constant(id)), 
     Expression.MakeBinary(ExpressionTypeDictionary[operatorType], Expression.Property(innerParameter, "Value"), Expression.Constant(value))), 
    innerParameter); 
var parameter = Expression.Parameter(typeof(FirstClass), "x"); 
var predicate = Expression.Lambda<Func<FirstClass, bool>>(
    Expression.Call(
     typeof(Enumerable), "Any", new Type[] { typeof(SecondClass) }, 
     Expression.Property(parameter, "MyList"), innerPredicate), 
    parameter); 
+1

あなたの提案は、さらに一歩私を得たが、私はバグがありだと思いますEF Core(バージョン1.0.0を使用しています)では、SQL照会で 'Expression.And'が'& 'に変換されます。代わりに 'Expression.AndAlso'を使用することで、SQL構文はうまくいき、すべてが期待通りに機能します。 –

+0

おっと、申し訳ありません、それは 'AndAlso'である必要があります、私はいつもそれらを台無しに:) –

関連する問題