我为搜索逻辑构建动态表达式树遇到了一个小问题。为实体自己的属性创建表达式树工作正常,但我不知道如何添加将按子实体属性过滤的表达式。
这是我的任务实体:
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进行过滤。
我已经失去了一些时间,试着靠自己寻找答案但没有结果。
任何帮助?
答案 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等)组合。
希望这有帮助。