我有这样的实体:
产品
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
价目表
public class PriceList
{
public int Id { get; set; }
public string Name { get;set; }
}
PriceListProduct
public class PriceListProduct
{
public int Id { get; set; }
public int PriceListId { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
问题是,如何使用LINQ获取不在价目表中的产品?
我的第一个想法是使用Contains,但产品列表可能大于100000,如果Contains翻译为像WHERE NOT IN子句这样的查询,SQL有大约2000个参数的限制,所以除了性能,我认为这不是最好的方法。
还有其他方法吗?我应该使用原始查询吗?
更新#1
我试图在@Indregaard回答之后了解GroupJoin。到目前为止,我有这个。
var productsWithNoPrice = db.Product()
.GroupJoin(db.PriceListProduct().Where(plp => plp.PriceListId == 2)
.Select(plp => plp.Product),
p => p.Id,
plp => plp.Id,
(p, product) => new { p.Id, Product = product })
.Where(p => !p.Product.Any())
.Select(p => p.Product);
使用过滤器
.Where(plp => plp.PriceListId == 2)
我正在使用ID 2过滤价格表中的产品。我认为这很接近,但SQL生成的查询会返回一些行,这些行对应于价目表中不存在的产品数量但每一行列为空。
基本上我需要的是像这样的查询
select * from Product p
left join PriceListProduct plp on plp.ProductId = p.Id and plp.PriceListId = 2
where plp.Id is null
答案 0 :(得分:3)
所以你正在寻找Antijoin。
手动方法可能是这样的:
var query =
from p in db.Products
join plp in db.PriceListProducts
on p.Id equals plp.ProductId into priceLists
where !priceLists.Any()
select p;
另一种方式:
var query = db.Products
.Where(p => !db.PriceListProducts.Any(plp => p.Id == plp.ProductId));
但最好的方法是在模型中创建所有导航属性
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<PriceListProduct> PriceLists { get; set; }
}
让EF为您创建查询
var query = db.Products.Where(p => !p.PriceLists.Any());
答案 1 :(得分:0)
你试过Join/GroupJoin吗? 我没有尝试过反对数据库来查看生成的sql是否有效/工作但是对于常规对象这样的东西是可行的。
var productsWithNoPrices = products.GroupJoin(productPriceList,
product => product.Id,
productprice => productprice.ProductId,
(product, productPrice) => new { Product = product, Prices = productPrice})
.Where(c=>!c.Prices.Any()).Select(c=>c.Product);
修改:根据您更新的问题,我认为您需要这样的内容:
var productsWithNoPrices = db.Products.GroupJoin(db.PriceListProducts.Where(c => c.PriceListId == 2),
product => product.Id,
productprice => productprice.ProductId,
(product, productPrice) => new { Product = product, Prices = productPrice }).Where(c=>!c.Prices.Any()).Select(c=>c.Product);
GroupJoin将在你的左表(db.Products)中进行更新,在右表中加入什么(db.PriceListProducts.xxxxx)(参数1):左表中的每个产品都将从右边获得匹配列表,结合产品ID(参数2和3),输出到匿名类型(参数4)。在没有产品价格的地方过滤所有这些并选择产品。这导致以下SQL,它似乎给出了期望的结果?
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Products] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[PriceListProducts] AS [Extent2]
WHERE (2 = [Extent2].[PriceListId]) AND ([Extent1].[Id] = [Extent2].[ProductId])
)