使用 LINQ 从产品列表中删除旧项目

Delete Old Items from Product List Using LINQ

我们有一个 Suppliers class 和一个 Products class。我们希望在供应商发布新产品目录时使用 Entity Framework Core 来更新我们的数据库。简化的 classes:

public class Supplier
{
    public Guid SupplierId { get; set; }
    public List<Product> Products { get; } = new List<Product>();
}
public class Product
{
    public string ItemCode { get; set; }
    public decimal ItemCost { get; set; }
    public Guid SupplierId { get; set; }
    public Supplier Supplier { get; set; }
}

我们希望先删除新目录中不在旧目录中的项目。我们尝试使用此 LINQ 查询找到那些项目

List<Product> discontinued = db.Products
.Where(e => !newCatalog
.Any(nc => (e.ItemCode == nc.ItemCode && e.SupplierId == nc.SupplierId))
.ToList();

然后我们删除使用

db.Products.RemoveRange(discontinued);

然而查询 returns 所有产品 Products.SupplierId != newCatalog.SupplierId。这将删除其他供应商的所有产品。

我们如何制定 LINQ 查询,以便我们只删除 newCatalog 中停产的项目?

正确的条件是

Where(e => e.SupplierId == supplierId && !newCatalog.Any(nc => nc.ItemCode == e.ItemCode))

这需要了解通过产品的SupplierId。可以用这样的东西提前提取:

var supplierId = newCatalog.Select(e => e.SupplierId).Distinct().Single();

这里的Select+Distinct+Single只是为了保证所有通过的产品都一样SupplierId。如果您不需要这样的强制执行,您可以简单地从第一个产品中获取它:

var supplierId = newCatalog[0].SupplierId;

在这两种情况下,最好提取它并将其放入查询之外的变量中。

另一个改进可能是用基于 Contains 的条件替换最有可能导致客户评估的 newCatalog.Any(nc => nc.ItemCode == e.ItemCode) 条件,希望转换为 SQL IN (...) 并在服务器。为此,您可以再次将新项目代码提取到查询外的新变量中:

var newItemCodes = newCatalog.Select(nc => nc.ItemCode);

那么查询中的最终条件将是:

Where(e => e.SupplierId == supplierId && !newItemCodes.Contains(e.ItemCode))