这是一个示例数据集:
OrderProduct
是一个表,其中包含属于给定订单的productIds。
注意: OrderProduct是一个数据库表,我正在使用EF。
OrderId,ProductId
1,1
2,2
3,4
3,5
4,5
4,2
5,2
5,3
我希望能够做的是找到一个包含仅我正在搜索的productIds的订单。因此,如果我的输入是productIds 2,3,那么我应该回到OrderId 5。
我知道如何对数据进行分组,但我不确定如何对该组执行选择。
这就是我所拥有的:
var q = from op in OrderProduct
group op by op.OrderId into orderGroup
select orderGroup;
不确定如何从这里开始
答案 0 :(得分:2)
乍一看,我会尝试这样的事情:
var prodIds = new[] {2, 3};
from o in context.Orders
where prodIds.All(pid => o.OrderProducts.Any(op => op.ProductId == pid))
select o
用简单的语言:“获取包含给定列表中每个ID的产品的订单。”
由于看起来您使用的是LINQ to SQL而不是LINQ to Entities,这是另一种方法:
var q = context.Orders;
foreach(var pid in prodIds)
{
q = q.Where(o => o.OrderProducts.Any(op => op.ProductId == pid));
}
不是使用单个LINQ语句,而是基本上构建查询零碎。
答案 1 :(得分:2)
IEnumerable<int> products = new List<int> {2, 3};
IEnumerable<OrderProduct> orderProducts = new List<OrderProduct>
{
new OrderProduct(1, 1),
new OrderProduct(2, 2),
new OrderProduct(3, 4),
new OrderProduct(3, 5),
new OrderProduct(4, 5),
new OrderProduct(4, 2),
new OrderProduct(5, 2),
new OrderProduct(5, 3),
};
var orders =
(from op in orderProducts
group op by op.OrderId into orderGroup
//magic goes there
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
select orderGroup);
//outputs 5
orders.Select(x => x.Key).ToList().ForEach(Console.WriteLine);
或者你可以在另一个答案中找到另一个版本,只需替换
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
在
where products.All(pid => orderGroup.Any(op => op.ProductId == pid))
第二个会有更好的性能提升约15%(我已经检查过了)
修改强>
根据上一次的需求变更,您需要的订单不包含您正在搜索的所有productIds,但正是那些而且只是那些productIds,我写了一个更新版本:
var orders =
(from op in orderProducts
group op by op.OrderId into orderGroup
//this line was added
where orderGroup.Count() == products.Count()
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
select orderGroup);
所以你唯一需要的是添加一个先决条件,确保集合包含相同数量的元素,它将适用于两个之前的查询,作为奖励我建议第3个版本最重要的条件:
where orderGroup.Select(x => x.ProductId).Intersect(products).Count() == orderGroup.Count()
答案 2 :(得分:0)
感谢StriplingWarrior的回答,我设法解决了这个问题。不确定这是否是最好的方法,但它确实有效。
List<int> prodIds = new List<int>{2,3};
var q = from o in Orders
//get all orderproducts that contain products in the ProdId list
where o.OrderProducts.All(op => prodIds.Contains(op.ProductId))
//now group the OrderProducts by the Orders
select from op in o.OrderProducts
group op by op.OrderId into opGroup
//select only those groups that have the same count as the prodId list
where opGroup.Count() == prodIds.Count()
select opGroup;
//get rid of any groups that may be empty
q = q.Where(fi => fi.Count()> 0);
(我正在使用LinqPad,这就是为什么查询看起来有点时髦 - 没有上下文等)