我正在尝试为通用存储库重构一些代码,该代码传递了一个过滤对象,该对象将过滤数据以及页面,排序等。
每个继承Filter
(例如CustomerFilter)都可以选择定义自己的表达式过滤器,该表达式过滤器将由存储库中的基类应用。
因此客户过滤器将具有以下属性:
public string CustomerId { get; set; }
public override Expression<Func<object, bool>> Predicate => c => ((Customer)c).Id == CustomerId;
然后,存储库将在存储库中运行过滤器,有点像这样(它还不是通用的!):
using (var context = new CustomerContext())
{
return await Filter<Domain.Customer>.ApplyAsync(filter, context.Customers.AsQueryable()).ConfigureAwait(false);
}
这行得通,但是我需要一种方法来更好地构建更复杂的示例的表达式。
例如,过滤器可以允许根据状态对客户进行过滤,但前提是要设置状态。
public string CustomerId { get; set; }
public State? CustomerState { get; set; }
public override Expression<Func<object, bool>> Predicate => c => (((Customer)c).Id == CustomerId) && (((Customer)c).State == CustomerState ?? (Customer)c).State);
这不仅变得一团糟,而且还有很多不必要的强制转换和括号。因此,我想做的是在getter中创建一个表达式生成器,它将以更简洁的方式构建表达式,例如if(State != null) { CustomerState == State; }
。但这就是我不确定如何进行的地方,所以如果有人可以帮助我,我将不胜感激。
答案 0 :(得分:1)
如果您想组合多个“条件”以应用于Where子句,则可以使用LinqKit库中的PredicateBuilder
这里是将两个条件与“或”子句组合在一起的示例
System.Linq.Expressions.Expression<Func<Domain.Question, bool>> codition1 = e => e.CategoryId == 1;
System.Linq.Expressions.Expression<Func<Domain.Question, bool>> condition2 = e => e.CategoryId == 2;
var combinedCondition = LinqKit.PredicateBuilder.Or(codition1, condition2);
//using combined condition in where clause....
queryable = queryable.Where(combinedCondition);
您可以使用 PredicateBuilder 类的其他方法(例如“ And”)来获取所需的组合条件...
答案 1 :(得分:0)
您可以将表达式与Linq Expressions API结合使用:
public Expression<Func<Customer, bool>> BuildExpression()
{
Expression<Func<Customer, bool>> predicate = c => c.Id == CustomerId;
if (State != null)
{
var parameter = predicate.Parameters.First();
var newBody = Expression.AndAlso(
predicate.Body,
Expression.Equal(
Expression.PropertyOrField(parameter, nameof(State)),
Expression.Constant(State)
));
predicate = Expression.Lambda<Func<Customer, bool>>(newBody, parameter);
}
return predicate;
}
在predicate
以上的代码中,是一个基本表达式,如果State
为null,则将使用该基本表达式。但是当设置State
时,我们提取表达式参数,并将&& c.State == State
添加到谓词主体