EF 4: Removing child object from collection does not delete it - why?

前端 未结 5 1335
执念已碎
执念已碎 2020-11-29 09:02

I use Entity Framework 4 and I have parent - child relation with \"Cascade Delete\" set. So i would expect when i remove a child from the parent that the child is deleted wh

相关标签:
5条回答
  • 2020-11-29 09:34

    I use this extension in order not to add a method in DAL just to delete an entity (code taken from http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx):

    public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships
    {
        RelationshipManager relationshipManager = entityToDelete.RelationshipManager;
    
        IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();
        if (relatedEnd == null)
        {
            throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship.");
        }
    
        var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
        if (query == null)
        {
            throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext.");
        }
    
        query.Context.DeleteObject(entityToDelete);
        collection.Remove(entityToDelete);
    }
    

    So I then delete an entity like Order.Products.Delete(prod).

    Constraints to use the extension are:
    - Entity must have relationships;
    - Entity must be attached to ObjectContext.

    0 讨论(0)
  • 2020-11-29 09:37

    If you make the relationship between child and parent an identifying one then you can remove child entities from the collection. You need to make the child's key a composite key containing the primary id key of the parent. That way EF knows it needs to remove the child.

    Identifying relationship basically says if the parent doesn't exist then the child has no meaning. This means EF knows it is safe to delete the child when the relationship is removed.

    See this question Identifying Relationship and inserting child entities causes "Cannot insert explicit value for identity column in table" and this one Is it possible to remove child from collection and resolve issues on SaveChanges?

    0 讨论(0)
  • 2020-11-29 09:40

    add context.DeleteObject(recipe) inside the loop

    0 讨论(0)
  • 2020-11-29 09:41

    You aren't deleting the object with the remove statement. Instead you are attempting to alter a record and make it an orphan (by setting the foreign key to null). The database has a non-null constraint on that column and prevents you from doing so.

    0 讨论(0)
  • 2020-11-29 09:50

    http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx explains exactly what happened to you.


    Assuming you have a class design something like this:

    sample class design

    Entity Framework will generate the required foreign key columns and add NOT NULL constraints to them because all Recipes will always be associated with exactly one ControlUnit.

    So at runtime you will have objects similar to the following layout:

    object diagram at runtime

    Now your code comes into play and deleted the relationship between the Recipe objects and their ControlUnit:

    objects with deleted relationships

    Trying to save at this moment, the database does not have a ControlUnit ID to put into the foreign key NOT NULL column. The current object state violates the class diagram above and cannot be saved to a database layout that has been generated under the assumption that every Recipe is associated with one ControlUnit. This is why the database refuses to save the changes and you see the exception.

    This also explains why it works when you uncomment the line deleting the entity: The entity is removed from the database along with its relationship, so no constraints are violated, therefore no exception.

    "But I set ON DELETE CASCADE on the relationship..."

    Yes, but that is only triggered on deletion of the object, not on deletion of the relationship. With ON DELETE CASCADE set, this should work:

    controlUnitRepository.DeleteObject(_controlUnit);
    // deletes the ControlUnit and all associated Recipe entities
    

    If you want to trigger deletion of the Recipe entities on deletion of their relationship with ControlUnit, your relationship should not be a simple association but rather a composition:

    updated class diagram with composition

    EF does not support this natively, but you can emulate the behaviour using identifying relationships. Once an entity is in an identifying relationship to a parent entity and that relationship is removed, the entity is removed as well. It seems this was your intention from the start. For more information on identifying relationship, see Implementing identifying relationships with EF4 where I implemented identifying relationships with EF4 and have linked to more reading material.

    0 讨论(0)
提交回复
热议问题