过滤但 属性 和子实体 属性

Filtering but property and child entity property

我在为搜索逻辑构建动态表达式树时遇到了一个小问题。为实体自己的属性创建表达式树工作正常,但我不知道如何添加将按子实体属性过滤的表达式。

这是我的任务实体:

public class Task: Entity
{
    public TaskType Type { get; set; }
    public TaskPriority Priority { get; set; }
    public int ProjectId { get; set; }
    public Project Project { get; set; }
}

这是项目实体:

public class Project: Entity
{        
    public int CustomerId { get; set; }
    public Customer Customer { get; set; }
}

以及构建动态表达式的逻辑:

public Func<TaskItem, bool> Build(IList<Filter> filters)
{
    ParameterExpression param = Expression.Parameter(typeof(TaskItem), "task");
    List<Filter> priorityFilter = FilterFilters(filters, "Priority");
    List<Filter> typeFilter = FilterFilters(filters, "Type");
    List<Filter> customerFilter = FilterFilters(filters, "CustomerId");

    Expression expression = null;

    // BuildExpression is a method which simply creates expression which is using Tasks properties (like Type or Priority)
    expression = BuildExpression(param, priorityFilter, expression);
    expression = BuildExpression(param, typeFilter, expression);

    // This part need's to be reworked
    ParameterExpression projectParam = Expression.Parameter(typeof(Project), "project");
    Expression projectCustomerExpression = Expression.Equal(Expression.PropertyOrField(projectParam, "CustomerId"), Expression.Constant(customerFilter[0].Value));
    Expression customerExpression = Expression.Equal(Expression.PropertyOrField(param, "Project"), projectCustomerExpression);
    Expression finall = expression != null ? Expression.AndAlso(expression, projectCustomerExpression) : projectCustomerExpression;         
    // End of filtering by CutomerId

    return Expression.Lambda<Func<TaskItem, bool>>(finall, param).Compile();
}

我不知道如何按 CustomerId 进行过滤。上面标记为 This part need's to be reworked 的代码部分可能是错误的,或者至少是它的最后一部分。这个想法是用一个将按 CustomerId 过滤的表达式来扩展现有表达式(这个由 BuildExpression 方法构建)。

我已经在这上面浪费了一些时间,自己尝试并寻找答案但没有结果。

有什么帮助吗?

由于您提供了最少的代码,您如何创建实际的表达式是未知的。因此,我将尝试为这种情况提供一个通用方法。

如果你想过滤 Task 的列表,那么你仍然需要使用相同的 ParameterExpression 类型 Task,就像你已经做的那样:

ParameterExpression param = Expression.Parameter(typeof(TaskItem), "task");

即使您想过滤 Project 的属性,也无需创建类型 Project 的另一个 ParameterExpression。相反,您只需要重用前者 ParameterExpression。请注意,如果我们构建如下所示的静态谓词,这也是我们不使用不同参数表达式的情况:

queryableTask.Where(t => t.Priority == TaskPriority.High && t.Project.CustomerId == 123);

现在要在导航(子)上动态构建过滤器 属性,关键是形成 左表达式 (即导航表达式 属性)正确。

假设我们的导航 属性 是点符号:Project.CustomerId。然后我们可以做这样的事情来为 属性:

创建 left 表达式
// We already have the following commented properties
// prop = "Project.CustomerId";
// ParameterExpression param = Expression.Parameter(typeof(TaskItem), "task");
var leftExpr = prop.Split('.')
                   .Aggregate<string, MemberExpression>(null, 
                      (acc, p) => acc == null 
                          ? Expression.Property(param, p) 
                          : Expression.Property(acc, p));

然后您可以像正常 属性 一样完成剩下的工作,例如创建 正确的表达式 并将它们与另一个定义运算符的表达式组合(等于,非等于等)。

希望对您有所帮助。