4

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:

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. 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.

I only have PersonRepository.

Kindly provide a solution or help me understand if I am getting any concept wrong.

  • 1
    It's not a good idea to use the same class for for domain model and EF model. The EF model should only provide a means for servicing the domain model. – JotaBe Jul 07 '14 at 11:22
  • @JotaBe How can we do this exactly? – Worthy7 May 13 '21 at 12:38

2 Answers2

2

That's a common problem when doing DDD with EF. Two solutions worked well for me so far:

  1. Return the removed instance from your DeleteContact method. 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.

  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.

dmusial
  • 1,504
  • 15
  • 14
1

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).

One possible solution is to make PersonId nullable in the Contact class:

public int? PersonId { get; set; }

Then, in your DbContext, override SaveChanges to automatically delete the orphaned records:

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.

Community
  • 1
  • 1
AJ Richardson
  • 6,610
  • 1
  • 49
  • 59