Search code examples
entity-frameworkcode-firstentity-framework-ctp5ef-code-first

EF 4 CTP 5: Trouble trying to remove an entity


I have created a model POCO class called Recipe; a corresponding RecipeRepository persists these objects. I am using Code First on top of an existing database.

Every Recipe contains an ICollection<RecipeCategory> of categories that link the Recipes and the Categories table in a many-to-many relationship. RecipeCategory contains the corresponding two foreign keys.

A simplified version of my controller and repository logic looks like this (I have commented out all checks for authorization, null objects etc. for simplicity):

public ActionResult Delete(int id)
{
    _recipeRepository.Remove(id);

    return View("Deleted");
}

The repository's Remove method does nothing but the following:

public void Remove(int id)
{
    Recipe recipe = _context.Recipes.Find(id);
    _context.Recipes.Remove(recipe);
    _context.SaveChanges();
}

Howevery, the code above does not work since I receive a System.InvalidOperationException every time I run it: Adding a relationship with an entity which is in the Deleted state is not allowed.

What does the error message stand for and how can I solve the problem? The only thing I try to achieve is deleting an entity.


@Ladislav: I have replaced ICollection<RecipeCategory> by ICollection<Category>. Accidentially, ReSharper refactored away the virtual keyword.

However, the problem remains — I cannot delete a Category from a Recipe entity. The following code does not persist the deletion of the categories to the database:

private void RemoveAllCategoriesAssignedToRecipe()
{
    foreach (Category category in _recipe.Categories.ToArray())
    {
        _recipe.Categories.Remove(category);
        category.Recipes.Remove(_recipe);
    }

    _context.SaveChanges();
}

I have debugged the code and can confirm that the collections are modified correctly — that is, they contain no elements after the loop (I have also used the Clear() method). After calling SaveChanges(), they are populated again.

What am I doing wrong?

(Maybe it is important: I am using the Singleton pattern to only have one instance of the context.)


Solution

  • I was able to solve the problem the following way:

    private void RemoveAllCategoriesAssignedToRecipe()
    {
        foreach (Category category in _recipe.Categories.ToArray())
        {
            Category categoryEntity = _categoryRepository.Retrieve(category.CategoryID);
    
            var recipesAssignedToCategory = categoryEntity.Recipes.ToArray();
            categoryEntity.Recipes.Clear();
    
            foreach (Recipe assignedRecipe in recipesAssignedToCategory)
            {
                if (assignedRecipe.RecipeID == _recipe.RecipeID)
                {
                    continue;
                }
    
                categoryEntity.Recipes.Add(assignedRecipe);
            }
    
            _context.Entry(categoryEntity).State = EntityState.Modified;
        }
    
        _recipe.Categories.Clear();
        _context.SaveChanges();
    }