使用关联覆盖实体删除
Posted
技术标签:
【中文标题】使用关联覆盖实体删除【英文标题】:Overriding entity deletion with associations 【发布时间】:2012-09-23 12:33:29 【问题描述】:我正在尝试通过覆盖DbContext.SaveChanges()
方法并撤消删除任何实现我的ISoftDelete
接口的实体来在我的项目中实现软删除功能。
interface ISoftDelete
bool IsDeleted get; set;
在SaveChanges()
方法中,我为每个处于“已删除”状态并实现ISoftDelete
的条目调用我的SoftDelete() 方法。:
var entries = this.ChangeTracker.Entries().Where(x => (x.State == EntityState.Deleted) && x.Entity is ISoftDelete)
.ToList();
entries.ForEach(SoftDelete);
我的SoftDelete()
方法如下:
private void SoftDelete(DbEntityEntry entry)
if (entry.State == EntityState.Deleted && entry.Entity is ISoftDelete)
entry.Reload();
var entity = (ISoftDelete)entry.Entity;
entity.IsDeleted = true;
entry.State = EntityState.Modified;
这将完美地工作,直到我遇到一个与其他事物具有一对一关联的实体。此时会抛出异常并出现此错误:
"来自 'ChildParent' AssociationSet 的关系在 “已删除”状态。给定多重约束,对应的 'Parent' 也必须处于 'Deleted' 状态。"
有没有办法获取该实体的所有关联并同时更改它们的已删除状态?
我已经尝试获取对实际关联实体的引用,但实体的 EntityState
设置为 Unchanged
而不是 Deleted
。
【问题讨论】:
我认为关联本身被标记为已删除(关联在 EF 中被视为单独的对象),而不是相关实体。现在,当 EF 尝试删除关联时,它不能,因为相关实体未标记为已删除。我假设外键不可为空,因此删除实体需要删除相关实体(级联删除)。您可以查看此线程:***.com/questions/10300156/…。它可能会有所帮助,因为它显示了如何获取相关对象。 对获取相关对象很有帮助,谢谢。但是,当尝试更改其中一个关系的状态时,我收到一个奇怪的错误,提示“如果关系的一端是 KeyEntry,则无法更改关系的状态。” 你看过this workaround吗? 【参考方案1】:一般情况下,您需要先软删除父子关系中的子项。从最顶层的父级开始,然后递归遍历子级。标记访问的每个项目,以便您可以跟踪它是否已被软删除(以防反向引用)。
如果您有“业务对象”概念,您可以添加Childs
和Parent
属性以便于导航。否则,您将不得不在每个具有非平凡子关系的父级上“手动编码”。
还要注意,使用一个 LINQ 语句,您无法控制实际的遍历。
我知道上面的工作似乎很多,但考虑一下如何在 EF 中设计一种机制来自动推断所需的关系信息?!你最终会正确地做这样的事情。
【讨论】:
以上是关于使用关联覆盖实体删除的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Data JPA(Hibernate) 跨映射表过滤关联实体?