5
votes

I have a some error : EF 4: Removing child object from collection does not delete it - why?

when i remove a child from the parent that the child is deleted when i call SaveChanges(), it gives the follow error message:

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.

But with DbContext and EF 4.1, the "context.DeleteObject(recipe)" does not exist.

Any suggestion ?

[EDIT]

    public void UpdateWithAttributes(Model model, IEnumerable<Entity> entities)
    {
        var modelOriginal = this.unitOfWork.Model.GetById(model.IModel);

        this.unitOfWork.Context.Entry(modelOriginal).CurrentValues.SetValues(model);
        UpdateEntityAttributeAssociations(modelOriginal, entities);

        this.unitOfWork.Commit();
    }

    public void UpdateEntityAttributeAssociations(Model model, IEnumerable<Entity> current)
    {
        unitOfWork.Context.Entry(model).Collection(m => m.Entities).Load();
ICollection<Entity> original = model.Entities; // perhaps .ToList() necessary

        // delete
        if (original != null)
        {
            List<Entity> toDelete = GetToDelete(original, current);

            foreach (Entity originalEntityToDelete in toDelete)
            {
                unitOfWork.Context.Entity.Remove(originalEntityToDelete);
            }
        }

        // add, update
        if (current != null)
        {
            foreach (Entity currentEntity in current)
            {
                // No need to set the UpdatedWhen. The trigger on the table will handle that.
                if (original.Where(originalEntity => originalEntity.IEntity == currentEntity.IEntity).FirstOrDefault() == null)
                {
                    model.Entities.Add(currentEntity);
                }
            }
        }
    }
2

2 Answers

1
votes

I guess that you are adding again what you have just deleted because removing from the DbSet also removes internally the entity from the child collection original. Then in the second loop you add the entity again. You could try to catch this situation like so:

public void UpdateEntityAttributeAssociations(Model model,
                                              IEnumerable<Entity> current)
{
    unitOfWork.Context.Entry(model).Collection(m => m.Entities).Load();
    ICollection<Entity> original = model.Entities; // perhaps .ToList() necessary

    // delete
    List<Entity> toDelete = null;
    if (original != null)
    {
        toDelete = GetToDelete(original, current);
        foreach (Entity originalEntityToDelete in toDelete)
        {
            unitOfWork.Context.Entity.Remove(originalEntityToDelete);
        }
    }

    // add, update
    if (current != null)
    {
        foreach (Entity currentEntity in current)
        {
            if (toDelete == null || !toDelete.Contains(currentEntity))
            {
                if (original.Where(originalEntity => originalEntity.IEntity == 
                               currentEntity.IEntity).FirstOrDefault() == null)
                {
                    model.Entity.Add(currentEntity);
                }
            }
        }
    }
}

I've also replaced your first line with explicit loading the child collection since your procedure to query the child entities manually looks unfamiliar to me, but I don't think that this is the problem (but I don't know).

Edit

I'm not sure if my code above helps to remove the exception you had. I don't know what happens if you add an entity to a collection which is already in Deleted state and if this could throw this exception.

If the code doesn't help you could test if you also have the problem without the second (the Insert) loop. And how looks GetToDelete exactly? And how look your Model and Entity class and their relationships? And is model.Entity indeed another collection than model.Entities (or is it a typo)?

2
votes

You have to call:

context.Recipes.Remove(recipe);

Where Recipes are DbSet<Recipe>.