3

자식 속성에 대해 필터링해야하는 목록이 있습니다. 필터 연산자는 동적이며 여러 필터/lambdas를 결합하기 위해 조건부 작성기를 사용합니다.중첩 된 속성이있는 동적 linq 표현식 트리

편의상

, 이제 나는이 같은 두 개의 클래스가 있다고 가정 해 봅시다 :

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, 운영자 유형과 값, 의사 코드는 다음과 같이 같은 것이라고 사용

를 참조 번호 123 인 123 eq 456 같은
"list of FirstClass".Where(param1 => 
    param1.MyList.Single(param2 => 
     param2.ReferenceId == "reference id").Value "operatorType" "value") 

실제 필터 것이다 뭔가 operatorType는 "EQ"이고 값이 경우 operat 456

이다

만 동적 표현식과 FirstClass 필터링, 또한

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

매력, 예를 들어, 다음과 같이 작동하거나 다음 작품 잘 평등이었다 나는 컴파일하려면 다음을하지만, 실제 데이터에 필터를 실행하여 EF 코어가를 반환받을 수있어

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 }); 

: ID를 필터링 (내 ExpressionTypeDictionary는 제공된 operatorType을 기반으로 ExpressionType 선택을위한 사전입니다) 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' 여야합니다. –