Entity Framework Core,从嵌套集合中删除项目

15

我有两个班级

 public class InvoiceRow
    {
        public int Id { get; set; }
        public int InvoiceId { get; set; }

        public int ProductId { get; set; }
        public virtual Product Product { get; set; }

        public int Amount { get; set; }
    }



   public class Invoice
    {
            public int Id { get; set; }
            private ICollection<InvoiceRow> _rows;
            public virtual ICollection<InvoiceRow> Rows => _rows ?? (_rows = new List<InvoiceRow>());
    }

我在仓储类中使用Update方法

  public void Update(Invoice record)
  {
            dB.Invoices.Update(record);
            dB.SaveChanges();
  }

它可以更新行集合中的值并添加新行,但是如果我传递的对象比数据库中的行数少,它不会删除项。最佳方法是什么?

3个回答

20

这是因为数据库中的行没有标记为删除。

只有新的或更改过的项目会被更新。集合中“缺失”的项目不被视为已删除。

因此,您需要自己标记要删除的项目。可以像这样进行:

public void Update(Invoice record)
{
    var missingRows = dB.InvoiceRows.Where(i => i.InvoiceId == record.Id)
                        .Except(record.Rows);
    dB.InvoiceRows.RemoveRange(missingRows);

    dB.Invoices.Update(record);
    dB.SaveChanges();
}

这会导致InvalidOperationException:无法跟踪实体类型“发票”的实例,因为已经有另一个具有相同键值{'Id'}的实例正在被跟踪。在附加现有实体时,请确保只附加一个具有给定键值的实体实例。考虑使用'DbContextOptionsBuilder.EnableSensitiveDataLogging'来查看冲突的键值。 - Oleksandr Khytrov
1
我找到了异常的原因,我们得到了两个分别被跟踪的实例。var missingRows = dB.InvoiceRows.Where(i => i.InvoiceId == record.Id).Except(record.Rows);dB.InvoiceRows.RemoveRange(missingRows);这样就可以工作了。 - Oleksandr Khytrov
1
我已经根据您的评论更新了答案。 - user4864425
1
这里不能使用 Except,因为它比较的是对象引用而不是值。也就是说,除非 InvoiceRow 实现了 IEquatable 接口并重写了 EqualsGetHashCode 方法。或者你可以将一个 IEqualityComparer 传递给 Except。或者你可以用 .Where(ir => !record.Rows.Any(rr => rr.Id == ir.Id)) 替换 .Except(record.Rows) - MarredCheese

2
我正在使用Entity Framework Core 6,以下代码适用于我。
public void Update(Invoice invoice)
{

        //1. valid invoice rows ids
        var validInvoiceRowIds = invoice.InvoiceRows.Select(ir => ir.Id).ToList();

        //2. missing invoice rows
        var missItems = _context.InvoiceRows
            .Where(ir => ir.InvoiceId == invoice.Id && !validInvoiceRowIds.Contains(ir.Id))
            .ToList();

        _context.RemoveRange(missItems);

        _context.Update(entity);
        _context.SaveChanges();

}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接