使用PredicateBuilder创建一个自包含的布尔表达式

时间:2012-06-17 15:59:38

标签: linq predicatebuilder

我正在试图弄清楚如何使用PredicateBuilder来确定Expression中是否存在一组特定的记录。因此,给定OrderId和ProductIds列表作为规范,我想知道Order的OrderDetail记录是否包含所有规范项。不只是其中一个或一些 - 而是所有这些。

所以我能做到:

var inner = PredicateBuilder.False<OrderDetail>();

foreach (int spec in specs)
{
   temp = spec;            
   inner = inner.Or(d => d.ProductId == temp);
}

var outer = PredicateBuilder.True<OrderDetail>();

outer = outer.And(d => d.OrderId == orderId);
outer = outer.And(inner);

但是,在得到结果后,我必须a)消除重复(因为在我的情况下,多个OrderDetails可以具有相同的ProductId)然后b)将结果计数与规格计数进行比较。所有这些都可以在Expression之外完成,但是有一种优雅的方法来评估Expression中的所有内容,结果是一个布尔值吗?

也就是说,我想让Expression自包含,以便它可以按原样传递,而我给它的那些不必知道如何进行“后处理”来弄清楚如果它是真的。

1 个答案:

答案 0 :(得分:0)

对于你给出的例子,我相信你可以通过不同的方式更简单地做到这一点。

不要使用OrderDetails,而是从规范开始,确保它们在OrderDetails集合中都是All。这一行代码将满足您确保特定orderID包含所有规范的要求,并且它并不复杂:

bool containsAllSpecs = specs.All 
    (s => orderDetails.Any (p => p.OrderId == orderId && p.ProductId == s));

我认为,尝试在OrderDetail类中构建Expression是不可能的,因为表达式仅应用于整个集合中的单个项目,因此不知道集合中的其他项目。

如果你真的想创建一个扩展来隐藏尽可能多的逻辑,你可以把它放在一个扩展中:

static class MyExtensions
{
    public static bool ContainsAllSpecs(this IEnumerable<OrderDetail> orderDetails,
        int orderId,
        IEnumerable<int> specs)
    {
        return specs
         .All (s => orderDetails.Any (p => p.OrderId == orderId && p.ProductId == s));
    }
}

然后你可以从代码中调用它:

bool containsAllSpecs = orderDetails.ContainsAllSpecs(orderId, specs);