在Entity框架中删除聚合根的子对象

时间:2014-07-07 00:39:43

标签: c# entity-framework repository domain-driven-design aggregateroot

之前可能会问过,但我似乎无法在网站上找到解决方案,所以我们走了:

以下是我的域模型的过度简化版本。我有2个类代表数据库中的2个表:

public Class Person
{
    public int Id { get; set;}
    public string Name { get; set;}
    public virtual List<Contact> Contacts { get; set;}

    public void AddContact(string value) 
    {
        //some validation code
        Contacts.Add(new Contact(value));
    }

    public void DeleteContact(Contact contact) 
    {
        //some validation code
        Contacts.Remove(contact);
    }
}

public Class Contact
{
    public int Id { get; set;}
    public string Value { get; set;}
    public virtual Person Person { get; set;}
    public int PersonId { get; set;}
}

现在Person是我的聚合根。我试图通过仅为聚合根创建存储库来遵循DDD主体。添加联系人工作正常。

我遇到的问题是删除联系人时。它给出了错误:

  

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

反正过去了吗?如果关系属性不可为空,那么实体框架不应自动删除联系人。

现在我知道从集合中删除与从上下文中删除它不同,但我不想从我的域模型中引用DbContext。

我只有PersonRepository。

请提供解决方案或帮助我理解我是否有任何错误概念。

2 个答案:

答案 0 :(得分:1)

您似乎遇到与this post相同的问题。基本上,当你从集合中删除联系人时,你实际上并没有删除它;你只是孤立它,并在此过程中,将其PersonId设置为null(当然,int是不可能的。)

一种可能的解决方案是在Contact类中使PersonId可以为空:

public int? PersonId { get; set; }

然后,在您的DbContext中,覆盖SaveChanges以自动删除孤立记录:

public override int SaveChanges()
{
    foreach (Contact contact in Contacts.Local.Where(c => c.PersonId == null))
    {
        Contacts.Remove(contact);
    }
    return base.SaveChanges();
}

免责声明:我还没有对该代码进行测试,但希望这是一个很好的起点。

答案 1 :(得分:1)

使用EF进行DDD时,这是一个常见问题。到目前为止,有两种解决方案对我有用:

  1. DeleteContact方法返回已删除的实例。该方法很可能是从拥有存储库的应用程序服务调用的。然后,您可以使用它从DbContext中删除实例。

  2. 如果您使用domain events,则可以使用其中一个通知其他人有关联系人移除的信息。然后,您可以在基础结构层中放置此事件的处理程序,这将从DbContext中删除联系人。