过滤但属性和子实体属性

时间:2017-11-18 09:08:57

标签: c# entity-framework lambda expression-trees

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

这是我的任务实体:

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的部分可能是错误的,或者至少是它的最后一部分。我们的想法是扩展现有的表达式(这个由BuildExpression方法构建的表达式),其表达式将按CustomerId进行过滤。

我已经失去了一些时间,试着靠自己寻找答案但没有结果。

任何帮助?

1 个答案:

答案 0 :(得分:2)

由于您提供了最少的代码,因此未知如何创建实际表达式。因此,我将尝试为此方案提供一般配方。

如果您想要过滤Task列表,那么您仍然需要使用ParameterExpression类型Task,就像您已经完成的那样:

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

即使您要对ParameterExpression的属性进行过滤,也无需再创建Project类型的Project。相反,您只需要重用前ParameterExpression。请注意,如果我们构建一个如下所示的静态谓词,那么我们也不会使用不同的参数表达式:

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

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

让我们说我们的导航属性是点符号:Project.CustomerId。然后我们可以做这样的事情来为属性创建左表达式

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

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

希望这有帮助。