简体   繁体   English

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

[英]Deleting a child object of an aggregate root in Entity framework

This might be asked before but I can't seem to find a solution on the site so here we go: 这可能是以前问过的,但我似乎无法在该站点上找到解决方案,所以我们开始:

Here is an oversimplified version of my domain model. 这是我的域模型的简化版本。 I have 2 classes representing 2 tables in the database: 我有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;}
}

Now Person is my aggregate root here. 现在,“人”是我的总根。 I am trying to follow the DDD principal by only making the repository for the aggregate root. 我试图通过仅使聚合根成为存储库来遵循DDD主体。 Adding contact works fine. 添加联系人可以正常工作。

The problem I have is when deleting the contact. 我的问题是删除联系人时。 It gives the error: 它给出了错误:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. 操作失败:由于一个或多个外键属性不可为空,因此无法更改该关系。 When a change is made to a relationship, the related foreign-key property is set to a null value. 对关系进行更改时,相关的外键属性将设置为空值。 If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted. 如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

Is there anyway past it. 无论如何还有过去。 If the relation property is non-nullable shouldn't entity framework automatically delete the contact. 如果关系属性为非空值,则实体框架不应自动删除联系人。

Now I know that deleting from the collection is not the same as deleting it from the context but I don't want to reference DbContext from my domain model. 现在,我知道从集合中删除与从上下文中删除并不相同,但是我不想从域模型中引用DbContext。

I only have PersonRepository. 我只有PersonRepository。

Kindly provide a solution or help me understand if I am getting any concept wrong. 请提供解决方案或帮助我了解是否有错误的概念。

It looks like you're having the same problem as in this post . 看来您遇到的问题与此帖子相同。 Basically, when you remove the contact from the collection, you are not actually deleting it; 基本上,当您从集合中删除联系人时,您实际上并没有将其删除。 you are only orphaning it, and in the process, setting its PersonId to null (which is not possible for an int , of course). 您只是孤立它,在此过程中,将其PersonId设置为null (当然,对于int是不可能的)。

One possible solution is to make PersonId nullable in the Contact class: 一种可能的解决方案是使ContactId类中的PersonId可为空:

public int? PersonId { get; set; }

Then, in your DbContext, override SaveChanges to automatically delete the orphaned records: 然后,在您的DbContext中,覆盖SaveChanges以自动删除孤立的记录:

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

Disclaimer: I haven't tested that code but hopefully it is a good starting point. 免责声明:我尚未测试该代码,但希望它是一个很好的起点。

That's a common problem when doing DDD with EF. 在使用EF进行DDD时,这是一个常见的问题。 Two solutions worked well for me so far: 到目前为止,有两种解决方案对我来说效果很好:

  1. Return the removed instance from your DeleteContact method. DeleteContact方法返回删除的实例。 The method is most probably called from an application service which holds a repository. 该方法最有可能从拥有存储库的应用程序服务中调用。 You can then use it to remove the instance from DbContext. 然后,您可以使用它从DbContext中删除实例。

  2. If you use domain events you can use one to notify others about contact removal. 如果您使用域事件 ,则可以使用一个事件来通知其他人有关联系人删除的信息。 You could then place a handler for this event in the infrastructure layer which would remove the contact from DbContext. 然后,您可以在基础结构层中放置此事件的处理程序,该处理程序将从DbContext中删除该联系人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM