【问题标题】:EF Find entities not in listEF查找不在列表中的实体
【发布时间】:2016-06-21 23:06:22
【问题描述】:

我有这个实体:

产品

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; }
}

价格表产品

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

【问题讨论】:

  • “不在价目表中”是什么意思?即不在表格中,或不在某个具体列表中?
  • 不在表中。例如,如果有 4 个产品(P1、P2、P3、P4)并且我有一个包含 P1 和 P3 的价目表,我怎样才能获得产品 P2 和 P4。

标签: asp.net-mvc entity-framework linq ef-code-first linq-to-entities


【解决方案1】:

你试过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)。在没有 productprice 的地方过滤所有这些并选择产品。这会产生以下 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])
)

【讨论】:

  • 谢谢,我想我很接近了,我正在使用 GroupJoin,但结果不是我所期望的,你能检查一下帖子的更新吗?我真的很感谢你的帮助!!
【解决方案2】:

所以你正在寻找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());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-01
    • 2018-09-07
    • 2016-02-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2021-12-11
    相关资源
    最近更新 更多