我正在尝试删除对象的层次结构:
客户 - >订单 - > 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>
那我在这里错过了什么?
答案 0 :(得分:1)
这是在迭代时修改数组的经典案例。当我们删除这样的孩子时:
o.items.forEach(oi => {
oi.entityAspect.setDeleted();
});
...每次调用setDeleted
时,它都会从父items
集合中删除子实体,这是正在迭代的集合。因此,下一次迭代会跳过其间的实体,实际上只有大约一半的实体被设置为删除。
这种情况的症状是包含已删除和已修改实体的混合的SaveBundle,以及(如果要删除父实体),当您尝试删除父项而不删除所有内容时,数据库中存在外键冲突孩子。
简单的解决方案是在迭代之前制作数组的副本,例如使用slice
:
o.items.slice().forEach(oi => {
oi.entityAspect.setDeleted();
});