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

时间:2017-09-22 07:25:06

标签: entity-framework linq linq-to-entities entity-framework-core

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

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

但是,查询会返回Products.SupplierId != newCatalog.SupplierId的所有产品。这会删除其他供应商的所有产品。

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

1 个答案:

答案 0 :(得分:2)

正确的条件是

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;

在这两种情况下,提取它并将其置于查询之外的变量中是件好事。

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

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

然后查询中的最终标准是:

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