LINQ:生成" AND"表达而不是" OR"当使用" CONTAINS"

时间:2014-08-16 21:03:40

标签: c# .net linq entity-framework

我有这个清单:

string[] countries = {
        "USA",
        "CANADA"
    };

当我运行此查询时:

query = (from user in db where
         user.Orders.Any(order => order.Price > 10 &&
                                      countries.Contains(order.DestinationCountry)))

输出是将订单发送到" USA"的用户列表。 "加拿大"。

但我希望将订单发送给" USA" " " CANADA"

我可以使用以下代码执行此操作,但我正在搜索纯粹的linq解决方案而没有任何 ForEach

foreach (country in countries) {
    query = (from user in query where
             user.Orders.Any(order => order.Price > 10 &&
                                      order.DestinationCountry == country));
}

数目:

一个。使用.Aggregate()

生成的查询就像For Each。

B中。where countries.All(c => user.Orders.Any(o => o.Price > 10 && o.DestinationCountry == c))

当国家列表中没有元素时(当我希望所有用户仅基于Price参数时),结果不正确,不考虑其他参数!


更新1:

我在发布之前尝试过 .All()而不是 .Contains(),它会返回0个用户。

更新2:

我已经更新了我的问题,使其更接近真正的问题。

让我们说国家不是唯一的参数。

更新3:

检查了一些答案并将结果添加到我的问题中。

4 个答案:

答案 0 :(得分:3)

所以你想要一个用户列表,这样列表中的所有国家都出现在订单目的地集中?

逻辑上,那将是:

query = from user in db
        where countries.All(c => user.Orders.Any(o => o.DestinationCountry == c))
        select ...;

然而,我并不相信EF会做你想做的事情。我不清楚正确的SQL查询是从什么开始的 - 至少以简单的方式。

答案 1 :(得分:3)

query = 
    db.Users.Where(user =>
        countries.All(country =>
            user.Orders.Any(order => 
                order.DestinationCountry == country)))

答案 2 :(得分:2)

你可以这样做:

query = (from user in db where
     user.Orders
     .Where(o => countries.Contains(o.DestinationCountry))
     .GroupBy(o => o.DestinationCountry)
     .Count() == countries.Count
);

我们的想法是只将订单发送到感兴趣的国家,然后按国家/地区分组,并检查组的数量是否等于国家数量。

答案 3 :(得分:1)

可以使用Enumerable.Aggregate

query = countries.Aggregate(query,
  (q, c) =>
  from user in q
  where user.Orders.Any(order => order.DestinationCountry == c)
  select user);

但实际上,这比你的foreach循环更难理解,所以我就是这样。

请注意,虽然我引用了Enumerable的成员,但Enumerable的成员实际上正在建立一个IQueryable<User>查询链,就像您的foreach循环一样,所以这不会导致过滤移动到客户端。