结合多个Linq表达式

我正在重构一些代码,试图让它更自我记录。 当前代码对OData服务进行查询,如下所示:

return context.MessageLog.Where ( x => ( x.Status == MessageStatus.Success || x.Status == MessageStatus.Failure ) && x.Direction == MessageDirection.Inbound && x.ResponseDate == new DateTimeOffset(new DateTime(1900, 01, 01)) ); 

我希望改变它以使用Linq Expressions。
我可以将所有逻辑移动到单个表达式中,并使代码运行context.MessageLog.Where(MessageIsPendingResponse); 。 但是,我想为不同的条件创建表达式: MessageIsProcessed (即现在处于成功或失败状态), MessageIsInboundResponseNotYetSent (响应日期为null)。 我可以将这些与多个where语句结合起来,如下所示:

 return context.MessageLog .Where(MessageLogExpression.MessageIsProcessed) .Where(MessageLogExpression.MessageIsInbound) .Where(MessageLogExpression.ResponseNotYetSent); 

MessageLogExpression是我用来包含这些预定义表达式的类)。

问题1

这是组合声明的最佳方式,还是首先冒险过滤错误的字段(例如,Linq是否将所有条件合并到一个查询中并允许查询引擎(以SQL术语)确定最佳执行计划;或者我们是否强制它首先在状态字段中过滤?

问题2

以上内容适用于我们有AND加入表达式的场景; 但我们怎么做OR呢? 我假设有一些方法来组合这些,但找不到任何明显的东西。 我怀疑这样的事情存在吗?

 return context.MessageLog.Where(new OrExpression(MessageIsSuccess,MessageIsFailure)); 

问题3

是否有一种很好的方法可以将表达式组合在另一个表达式定义中; 例如下面的代码(只有编译的版本)?

 public static Expression<Func> MessageIsPendingResponse { get { Expression<Func> expr = x => MessageIsProcessed(x) && MessageIsInbound(x) && ResponseNotYetSent(x); return expr; } } 

附录:上述表达的代码:

 public class MessageLogExpression { public static Expression<Func> MessageIsProcessed { get { Expression<Func> expr = x => ( x.Status == MessageStatus.Success || x.Status == MessageStatus.Failure ); return expr; } } public static Expression<Func> MessageIsInbound { get { Expression<Func> expr = x => x.Direction == MessageDirection.Inbound; return expr; } } static readonly DateTimeOffset NullDate = new DateTimeOffset(new DateTime(1900, 01, 01)); public static Expression<Func> ResponseNotYetSent { get { Expression<Func> expr = x => x.ResponseDate == NullDate; //todo: test if this works or if I have to define the value within the expression return expr; } } } 

关于#1 – 就使用Linq to Entities的EF而言,我希望EF能够创建相同的查询,无论我将其分成多个条件还是一切都在一个中。 即使它不会 – 一个SQL数据库可能仍然会产生相同的查询执行计划,因为它有自己的优化器。

关于其他问题,我们正在使用基于此博客文章的帮助程序类: http : //www.albahari.com/nutshell/predicatebuilder.aspx

 public static class PredicateBuilder { public static Expression> True() { return (Expression>) (input => true); } public static Expression> False() { return (Expression>) (input => false); } public static Expression> Or(this Expression> expression1, Expression> expression2) { InvocationExpression invocationExpression = Expression.Invoke((Expression) expression2, expression1.Parameters.Cast()); return Expression.Lambda>((Expression) Expression.OrElse(expression1.Body, (Expression) invocationExpression), (IEnumerable) expression1.Parameters); } public static Expression> And(this Expression> expression1, Expression> expression2) { InvocationExpression invocationExpression = Expression.Invoke((Expression) expression2, expression1.Parameters.Cast()); return Expression.Lambda>((Expression) Expression.AndAlso(expression1.Body, (Expression) invocationExpression), (IEnumerable) expression1.Parameters); } } 

这非常好用,因为它可以帮助您轻松地组合表达式。 你可以从PredicateBuilder.True().And(... expression1 ...).And(...)...如果你想合并OR表达式,你可以用false开头: PredicateBuilder.False().Or(...)...

这意味着对于Q3,您可以:

 public static Expression> MessageIsPendingResponse { get { Expression> expr = PredicateBuilder.True() .And(MessageIsProcessed) .And(MessageIsInbound) .And(ResponseNotYetSent) ; return expr; } }