从聚合根和数据库持久化中删除子节点
本文关键字:持久化 删除 子节点 数据库 | 更新日期: 2023-09-27 18:04:45
(这可能是重复的,但我在我读过的其他问题中没有找到任何令人满意的答案)
我需要一些关于如何删除聚合根的子实体可以传播到数据库层的指导。我想到/读到过几种不同的方法来处理它:
-
将移除的子元素单独保存。让存储库在保存时删除集合中的所有项。
-
直接调用某种数据映射层或存储库
-
执行存储库/UoW可能提供/侦听的某种委托/事件。
-
什么也不做。让工作单元或存储库将整个聚合根与"非脏"副本进行比较。
值得注意的是,我真正的聚合根实现包含多个可能被删除的子集合。
为清楚起见,这里有一个简单的例子:
public class AggregateRoot
{
private List<ChildEntity> _children;
public IEnumerable<ChildEntity> Children
{
get
{
return _children;
}
}
public void RemoveChild(ChildEntity child)
{
_children.Remove(child);
// What to do here?
// Option 1: Keep removed children i separate collection. Let
// the repository remove them on save.
RemovedChildren.Add(child);
// Option 2: Call some kind of data mapping layer or repository directly
_childRepository.Delete(child);
// Option 3: Execute some type of delegate/event that a repository
// may provide/listen to.
_onChildRemoved(this, child);
// Option 4: Do nothing. Let the Unit of work or repository compare
// the whole aggregate root with a "non-dirty" copy.
}
}
选项1和2我认为不是很优雅。
选项4很好,因为我不需要在聚合根中实现任何逻辑,但由于我的实际实现相当大,我必须比较很多属性和集合。
我倾向于选择3。它的问题是,它可能需要很多委托/事件。也许我可以实现一个通用的委托/事件。
这一定是一个相当常见的问题,但我看到的例子却少得惊人。你会如何处理这个问题?
选项1:我猜在你的业务中没有RemovedChildren这样的概念,所以在我看来聚合不应该包含这样的集合。请注意,有时可能会有像ChildrenHistory, HistoricalChildren这样的概念
选项2:我多次读到聚合不应该使用存储库,聚合不应该注入任何服务。但是,您可以使用双重分派模式并提供方法签名,如:
public void RemoveChild(ChildEntity child, IChildRepository repository)
{
// check conditions, business logic etc
// remove using repository
然而,它迫使调用者提供存储库,这在某些情况下可能很难实现
选项3:我以前没有使用事件来实现这个目的。但对我来说还不错。您可以使用事件总线通知感兴趣的存储库有关实体删除。
选项4:在我看来,这是最好的方式,UoW应该处理项目删除。您可以通过在它们上设置某种标志或通过将它们的ParentId设置为0来标记您的实体被删除(这就是EF在引擎盖下所做的)。在提交时,您可以检查加载到内存中的所有对象,并删除那些标记为删除的对象。这迫使我们在域层中编写最少的基础结构代码,但是我们需要在UoW中编写额外的代码来删除孤儿。