c# - 具有嵌套属性的动态 linq 表达式树

标签 c# entity-framework linq linq-expressions expressionbuilder

我有一个列表,我必须根据子属性对其进行过滤。过滤器运算符是动态的,我正在使用谓词生成器来组合多个过滤器/lambda。

为简单起见,假设我有两个这样的类:

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 eq 456,其中引用 id 为 123,operatorType 为“eq”,值为 456。

如果运算符只是相等,那么下面的工作就很好:

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

此外,仅在 FirstClass 上使用动态表达式进行过滤,就像一个魅力,例如在 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 Core 对真实数据执行过滤器会返回 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);

任何建议表示赞赏:)

最佳答案

我想而不是像这样表达

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

关于c# - 具有嵌套属性的动态 linq 表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40363333/

相关文章:

c# - EF Core 已跟踪具有相同 id 的实体

c# - 使用 LINQ 查询自动检查 NULL 关系

java - 此 C# 泛型方法模式的等效 Java 实现是什么

c# - 更新 Entity Framework 中的嵌套对象

.net - EF4 如何在事务中包装 2 个更新

c# - 在 LINQ 中忽略参数的正确方法是什么?

c# - Select 和 SelectMany 的区别

c# - 如何测试这个业务逻辑

c# - Silverlight 作为桌面应用程序?

c# - 将占位符文本添加到文本框