过滤但 属性 和子实体 属性
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));
然后您可以像正常 属性 一样完成剩下的工作,例如创建 正确的表达式 并将它们与另一个定义运算符的表达式组合(等于,非等于等)。
希望对您有所帮助。
我在为搜索逻辑构建动态表达式树时遇到了一个小问题。为实体自己的属性创建表达式树工作正常,但我不知道如何添加将按子实体属性过滤的表达式。
这是我的任务实体:
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
。然后我们可以做这样的事情来为 属性:
// 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));
然后您可以像正常 属性 一样完成剩下的工作,例如创建 正确的表达式 并将它们与另一个定义运算符的表达式组合(等于,非等于等)。
希望对您有所帮助。