我们有一个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
中已停止的项?
答案 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))