setDeleted循环导致saveChanges调用中的修改实体

时间:2017-03-08 22:54:23

标签: c# entity-framework typescript breeze

我正在尝试删除对象的层次结构:

客户 - >订单 - > OrderItems-> OrderItemOptions

我设置了一个简单的嵌套循环,试图以“正确”顺序执行操作,因为它们必须在数据库中完成 - 在删除父级之前先删除子记录。

这是循环:

deleteCustomer(customer: Customer): Promise<void> {
  return this.getCustomerOrderHistory(customer.id).then(orders => {
    orders.forEach(o => {
      o.items.forEach(oi => {
        oi.options.forEach(opt => opt.entityAspect.setDeleted());
        oi.entityAspect.setDeleted();
      });
      o.entityAspect.setDeleted();
    });
    customer.entityAspect.setDeleted();
  });
}

问题是,当每个级别的父对象都是setDeleted()时,标记为“已修改”的一组重复实体记录将添加到EntityManager缓冲的更改中。然后,当我调用saveChanges时,ASP.NET / EF后端会抛出异常,因为在执行与这些修改记录相对应的UPDATE语句时,DELETE已经发生,因此UPDATE失败并且找不到FK异常。< / p>

那我在这里错过了什么?

1 个答案:

答案 0 :(得分:1)

这是在迭代时修改数组的经典案例。当我们删除这样的孩子时:

    o.items.forEach(oi => {
      oi.entityAspect.setDeleted();
    });

...每次调用setDeleted时,它都会从父items集合中删除子实体,这是正在迭代的集合。因此,下一次迭代会跳过其间的实体,实际上只有大约一半的实体被设置为删除。

这种情况的症状是包含已删除和已修改实体的混合的SaveBundle,以及(如果要删除父实体),当您尝试删除父项而不删除所有内容时,数据库中存在外键冲突孩子。

简单的解决方案是在迭代之前制作数组的副本,例如使用slice

    o.items.slice().forEach(oi => {
      oi.entityAspect.setDeleted();
    });