【问题标题】:Deleting a child object of an aggregate root in Entity framework在实体框架中删除聚合根的子对象
【发布时间】:2014-07-07 00:39:43
【问题描述】:

这可能以前被问过,但我似乎无法在网站上找到解决方案,所以我们开始吧:

这是我的域模型的过度简化版本。我有 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。

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

【问题讨论】:

  • 对于域模型和 EF 模型使用同一个类并不是一个好主意。 EF 模型应该只提供一种服务领域模型的方法。
  • @JotaBe 我们如何才能做到这一点?

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


【解决方案1】:

这是使用 EF 进行 DDD 时的常见问题。到目前为止,两种解决方案对我来说效果很好:

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

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

【讨论】:

    【解决方案2】:

    您似乎遇到了与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();
    }
    

    免责声明:我尚未测试该代码,但希望这是一个好的起点。

    【讨论】:

    • 没用。 WillCascadeOnDelete() 在您删除聚合根时有效,但在这种情况下无效。我只想删除一个子对象
    • 当然,傻我。我已经更新了我的答案;希望这更相关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多