Removing entity from a Related Collection

I have seen this misunderstanding starting to popup more often on how to delete an entity from a related collection. Suppose we have the following entity data model where a Person has many Phones identified by 1-to-many association as shown.

image

Problem: You have an existing Phone entity that you want to remove from the customer’s Phone collection

So let’s see how someone just walking into EF does it and assumes that code should works.

image

In the above code, I am creating a new customer and phone entity, adding the new phone to the customer’s Phone collection followed by adding the entire customer object graph to the ObjectContext. When I call SaveChanges, EF inserts a new customer along with its related phone. Now to delete the phone, I am simply removing the phone from the Phone Collection of the customer and then call SaveChanges. When you do that you get the following exception.

image

Now you wonder why did you get a failed delete and what is this exception saying? Essentially when you remove the phone from the customer’s phone collection, you are simply detaching the relationship between the phone and the customer but actually not deleting the phone itself. So when you try to save the changes, EF says oh wait, I can’t delete this relationship because a phone must belong to a customer because the customerId property on the Phone is not nullable.

Now that i have explained you what the problem is, I kept on wondering why developers thought removing something from a collection meant deleting the entity itself? Actually the answers lies in the way how we initially added the phone to the customer’s phone collection. Notice in the above code, to create a new phone we simply add the phone to the customer's phone collection which basically not only attaches the phone to the customer’s phone collection but also inserts the phone.  This leads the developers that they can apply the same concept to remove where removing a phone would actually mark it for deletion.

The correct way to remove the phone is to mark it for deletion. When you delete the phone, EF will automatically detach the phone from any of its relationship. Code below shows the correct code.

image

In the above code, after deleting the phone, I am displaying the total phones for the customer which is 0 because EF automatically removes the phone from the customer’s phone collection.

NOTE: There are edge cases where removing an entity from a collection also marks it for deletion like in the case of identifying relationship.

2 Comments

  • Hi,
    why does this also happens when I try to update a Collection?
    I've got a simple example like your on a MVC2 app. I've got a edit page that shows the Customer details, and also shows the the a list fields for each row of phones.

    When I submit the page, use the TryUpdateModel and call savechanges I get this exception. Could you give some guidance on how to overcome this?

    Thanks,
    Bruno

  • The reason why developers do run in to this is because you can add and update items in the collections from within the parent entity itself. Thus, delete seems natural.

    The reason why a delete in this way would be usable is because you would really like to not use the context within a POCO, as it should be persistence ignorant. So, you are left with the choice of either injecting a repository or service into the entity itself, which might or might not be a problem, depending on your design, or doin all these operations outside the entity.

    Now, if you do all these operations outside the entity, you will also be moving a lot of logic which problably should be in the entity to the outside, and you are left with parts of the business logic in the entity, and other parts of the BL outside in services.

Comments have been disabled for this content.