EF代码优先:如何在跟踪DDD时从实体的Collection中删除一行?

所以这是场景:

DDD声明您使用存储库来获取聚合根,然后使用它来添加/删除它拥有的任何集合。

添加很简单,您可以在要添加的Collection上简单地调用.Add(Item item) 。 保存时,会在数据库中添加一个新行。 但是,删除是不同的 – 调用.Remove(Item item)不会从数据库中删除该项,它只是删除外键。 所以,虽然,是的,它在技术上不再是集合的一部分,它仍然在数据库中。

阅读,唯一的解决方案是使用数据上下文删除它。 但根据DDD,域对象不应该知道数据上下文,因此删除必须在域外进行。

什么是正确的方法? 或者让数据库中的孤儿可以接受(也许是运行例程来清除它们)?

我已经通过使用域事件在我正在处理的应用程序中解决了这个问题; 一个DDD概念埃里克埃文斯说应该在他的书中。

虽然不允许域对象知道对象上下文,但IDomainEventHandler是 – 因此我有一个DomainObjectDeletionHandler ,它在控制返回到我的应用程序层之前从对象上下文中删除’已删除’对象,并保存更改。

有关更多信息,我写了一篇关于我的域事件实现的博客 ,以及我如何将所有内容连接在一起。

希望有所帮助:)

编辑

例如,如果您有一个Order类,其OrderItems集合类型为OrderItem

 public class Order { // Other stuff public void RemoveOrderItem(int orderItemId) { var orderItemToRemove = OrderItems.First(oi => oi.Id == orderItemId) OrderItems.Remove(orderItemToRemove); DomainEvents.Raise(new OrderItemRemoved(orderItemToRemove)); } } 

从集合中删除子实体时,EF会将其保留为孤立,只删除外键。

如果您不想使用DbContext显式删除它,您可以使用所谓的“识别关系”( http://msdn.microsoft.com/en-us/library/ee373856.aspx底部)。

诀窍是在子项上设置复合主键,包括父键的主键。

一旦你这样做,当从父集合中删除实体时,它也将从表中删除。

我不知道这是否是设计的,但如果详细信息对象具有包含其主对象的键列的复合键,则如果从主对象的集合中删除它,它将自动删除。 如果您有一个带有OrderID键和ICollection OrderLines导航属性的Order对象,请为OrderLine提供一个包含OrderID和OrderLineID的复合键。

但由于我不知道我是否可以依赖它,我自己使用的解决方案是让EF以它的方式处理它,并在调用SaveChanges时修复’detached’(不是EF术语)细节对象(),枚举所有已修改的实体并根据需要将状态更改为已删除。

为什么不使用两个存储库?

 var parent = ParentRepo.Get(parentId); parent.Children.Remove(childId); // remove it from the property Collection ChildRepo.Delete(childId); // delete it from the database ParentRepo.Commit(); // calls underlying context.SaveChanges() 

假设您通过IOC / DI共享上下文,使用一个repo调用commit将为两者提交,否则只需调用ChildRepo.Commit