所以这是场景:
DDD声明您使用存储库来获取聚合根,然后使用它来添加/删除它所拥有的任何集合。
添加很简单,只需在要添加的.Add(Item item)
上调用Collection
即可。保存时,会在数据库中添加一个新行。但是,删除是不同的 - 调用.Remove(Item item)
不会从数据库中删除该项,它只是删除外键。所以,虽然,是的,它在技术上不再是集合的一部分,它仍然在数据库中。
阅读,唯一的解决方案是使用数据上下文删除它。但根据DDD,域对象不应该知道数据上下文,因此删除必须在域外进行。
正确的方法是什么?或者让数据库中的孤儿都可以接受(也许正在运行例程来清除它们)?
答案 0 :(得分:11)
我已经使用domain events在我正在处理的应用程序中解决了这个问题; DDD概念Eric Evans said应该出现在他的书中。
虽然不允许域对象知道对象上下文,但IDomainEventHandler
是 - 我因此得到一个DomainObjectDeletionHandler
,它在控制返回之前从对象上下文中删除'已删除'对象我的应用程序层和更改已保存。
有关更多信息,我写了a blog关于我的域事件实现以及我如何将所有内容连接在一起。
希望有所帮助:)
修改强>
例如,如果您的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));
}
}
答案 1 :(得分:5)
从集合中删除子实体时,EF会将其保留为孤儿,只删除外键。
如果您不想使用DbContext显式删除它,您可以使用所谓的“识别关系”(底部为http://msdn.microsoft.com/en-us/library/ee373856.aspx)。
诀窍是在子项上设置复合主键,包括父键的主键。
一旦你这样做,当从父集合中删除实体时,它也将从表中删除。
答案 2 :(得分:3)
我不知道这是否是设计的,但如果详细信息对象具有包含其主对象的键列的复合键,则如果从主对象中删除它,它将自动删除。采集。如果您有一个带有OrderID键和ICollection OrderLines导航属性的Order对象,请为OrderLine提供一个包含OrderID和OrderLineID的复合键。
但是由于我不知道我是否可以依赖它,我自己使用的解决方案是让EF按照它的方式处理它,然后修复分离的问题' (不是EF术语)调用SaveChanges()时的详细对象,枚举所有已修改的实体并根据需要将状态更改为已删除。
答案 3 :(得分:0)
为什么不使用两个存储库?
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
。