I recently started learning Entity Framework and OData, and while there has been a learning curve, most problems seemed possible to solve without asking for help. This problem that I have has stumped me for over a day and I cannot find in the documentation what I am looking for.
The project is a simple Movie Database; Movies have a director and actors, and 'Film Professionals' have directing and acting credits for movies. When I try to delete a movie though, either I get an error saying:
"Adding a relationship with an entity which is in the Deleted state is not allowed."
or everything runs without throwing an error, but the state of the actors/director are reverted back to where they were before the delete call.
Here is the code that I am working with:
protected IHttpActionResult OnDelete(int key)
{
if (!Initialized) return NotFound();
var entity = DeleteOperation(key, DbContext);
if (entity == null) return NotFound();
DbSet.Remove(entity);
DbContext.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
}
protected override Movie DeleteOperation(int key, MovieContext movieContext)
{
var removeMovie = movieContext.Movies.FirstOrDefault(key, true, "Cast", "Director");
if (removeMovie == null) return null;
if (removeMovie.Cast != null)
{
foreach (var actor in removeMovie.Cast)
{
actor.Actor =
movieContext.Movies.Any(m => m.Key != removeMovie.Key && m.Cast.Any(c => c.Key == actor.Key));
}
}
if (removeMovie.Director != null)
{
removeMovie.Director.Director =
movieContext.Movies.Any(m => m.Key != removeMovie.Key &&
m.Director.Key == removeMovie.Director.Key);
}
return movieContext.Movies.FirstOrDefault(key, false);
}
public static T FirstOrDefault<T>(this DbSet<T> dbset, int key, bool disableTracking, params string[] include)
where T : ModelBase
{
if (dbset == null) return null;
var query = disableTracking ? dbset.AsNoTracking() : dbset.AsQueryable();
if (include.Length <= 0) return query.FirstOrDefault(e => e.Key == key);
var i = 1;
try
{
for (i = 0; i < include.Length; i++)
{
query = query.Include(include[i]);
}
return query.FirstOrDefault(e => e.Key == key);
}
catch (Exception)
{
throw new Exception("Include value '" + include[i] + "' has no context");
}
}
I have a feeling the actor/director state reverting back has to do with the call of .AsNoTracking()
on my database context, but without doing that, I get the aforementioned error every time. From my understanding, I need to essentially detach both Cast
and Director
from the Movie
entity, but I don't know the proper syntax.
So the solution that I came up with was to create a new instance of the database context within a
using
statement. The problem was that I was using the same instance of the database context for theDeleteOperation
as I was in theOnDelete
. This cleared up all errors and let me save the changes to the entities.