C# LINQ:生成";及;表达式而不是“引用”;或;当使用;包括「;

C# LINQ:生成";及;表达式而不是“引用”;或;当使用;包括「;,c#,.net,linq,entity-framework,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.Destinati

我有以下清单:

string[] countries = {
        "USA",
        "CANADA"
    };
运行此查询时:

query = (from user in db where
         user.Orders.Any(order => order.Price > 10 &&
                                      countries.Contains(order.DestinationCountry)))
输出是已将订单发送到“美国”或“加拿大”的用户列表

但我想要同时向“美国”和“加拿大”发送订单的用户列表

我可以使用下面的代码来实现这一点,但我正在搜索一个没有任何ForEach的纯linq解决方案:

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

A.使用.Aggregate()


生成的查询与每个查询类似

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


当国家/地区列表中没有元素时(当我希望所有用户仅基于价格参数时),结果不正确,并且不考虑其他参数


更新1:

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

更新2:

我已经更新了我的问题,使之更接近真实问题

假设国家不是唯一的参数

更新3:


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

那么您想要一个用户列表,以便列表中的所有国家/地区都出现在订单目的地集中

从逻辑上讲,这将是:

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

但是,我不相信EF会做你想做的事情。我不清楚正确的SQL查询应该从什么开始-至少用一种简单的方式。

你可以这样做:

query = (from user in db where
     user.Orders
     .Where(o => countries.Contains(o.DestinationCountry))
     .GroupBy(o => o.DestinationCountry)
     .Count() == countries.Count
);
这样做的目的是只保留发送给感兴趣国家的订单,然后按国家分组,并检查分组的数量是否等于国家的数量。

可以使用:

query = 
    db.Users.Where(user =>
        countries.All(country =>
            user.Orders.Any(order => 
                order.DestinationCountry == country)))
但事实上,这比您的
foreach
循环更难理解,所以我就这么说吧


请注意,尽管我引用了
Enumerable
的成员,但
Enumerable
的成员实际上正在构建一个
IQueryable
查询链,就像您的
foreach
循环一样,因此这不会导致过滤移动到客户端。

为了清楚起见,如果用户的订单同时发送到美国和加拿大,该怎么办nd其他国家,您仍然需要该用户吗?也就是说,您是否需要仅向美国或加拿大发送订单的用户,或者希望向我们发送订单的用户,以及向加拿大发送订单的用户(不管该用户是否也向其他任何地方发送订单)?@LasseV.Karlsen他们应该向美国和加拿大发送订单。如果他们向另一个国家发送订单,这没关系,也没关系。我的回答是
.Aggregate
,道格拉斯/乔恩·斯基特的回答是
国家,功能完全相同。所有的
行为就像你的
foreach
版本:那也不一样如果没有国家/地区,请对价格进行过滤。你能更新价格,使其更符合你想要实现的目标吗?我不清楚你期望的结果是什么。在某些特定情况下是清楚的,但不是一般逻辑应该是什么。@JonSkeet非常感谢你的回答。我更新了我的问题。你认为这是正确的吗如果涉及到任何其他参数,解决方案就可以工作?@AfshinGh为什么不可以?我不知道这个答案是否有效(原因与这个答案中已经提到的相同),但我不明白为什么任何额外的过滤器在这里会有任何不同。@AfshinGh:hvd说什么,基本上:)@jonsket当CountriesList中没有元素时(当我希望所有用户都基于其他参数,并且不需要此参数时)“这个结果是不正确的,没有考虑其他的参数!”AfsHunh:这是你第一次提到国家列表是空的情况。你可能想考虑使用一个单独的查询来解决这个问题。非常感谢你的回答。我已经更新了我的问题。你认为这个解决方案是否有效?是否涉及其他参数?CountriesList中没有元素时(当我希望所有用户都基于其他参数且不需要此参数时),结果不正确,未考虑其他参数!我的回答是针对您问题的原始版本的。如果您想要有效的解决方案,您可能需要打开另一个问题,并正确表述您的全部要求。非常感谢您的回答。如果可能,我正在尝试避免GroupBy。我已更新了我的question。如果涉及到任何其他参数,您认为此解决方案有效吗?@AfshinGh:为什么您试图避免
GroupBy
?您是否尝试过此方法,并发现由于某种原因查询速度太慢?非常感谢您的回答。正如您所说,它看起来像ForEach,所有数据都将移动到客户端。因此我认为ForEach是更好。@AfshinGh不,我确实认为
foreach
在可读性方面更好,但在正确性方面不更好:它们做完全相同的事情,并且都会导致在服务器端执行筛选。我的最后一句话中有一个“not”,我想您错过了。:)看起来很有趣,我将尝试这个,并将生成的查询与其他答案进行比较。谢谢。生成的查询与ForEach一样。谢谢。
query = countries.Aggregate(query,
  (q, c) =>
  from user in q
  where user.Orders.Any(order => order.DestinationCountry == c)
  select user);