将表达式<Func <object,bool >>作为属性

时间:2019-06-19 08:23:58

标签: c# entity-framework linq generics

我正在尝试为通用存储库重构一些代码,该代码传递了一个过滤对象,该对象将过滤数据以及页面,排序等。

每个继承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; }。但这就是我不确定如何进行的地方,所以如果有人可以帮助我,我将不胜感激。

2 个答案:

答案 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添加到谓词主体