Using the Entity Framework: Delete Operation (Quick Reference)

How to Use the Entity Framework to Delete Records in a Relational Database

This quick reference is for those who are trying out the Entity Framework and want examples of how to perform everyday CRUD tasks. We’ll take a look at how to delete objects and associated objects using the Entity Framework.

Quick Reference Setup

Entity Framework & Linq to Entities: “Movies” Example Setup contains diagrams representing the database structure, entity data model, and entity object model used in the following code examples.

Delete a Movie object using the Entity Framework

private static MovieEntities _entities = new MovieEntities();

static void Main(string[] args)
{
     Movie movieToDelete = 
          (from m in _entities.MovieSet
           where m.Title == "The Princess Bride"
	   select m).First();

     _entities.DeleteObject(movieToDelete);
     Console.WriteLine("--> {0}: Marked as Deleted in Model",
          movieToDelete.Title);
     Console.WriteLine("Entity State: {0}",
          movieToDelete.EntityState); // Deleted

     _entities.SaveChanges();
     Console.WriteLine("\n--> {0}: 
          Deleted from Model and Datasource",
          movieToDelete.Title);
     Console.WriteLine("Entity State: {0}",
          movieToDelete.EntityState); // Detached
     Console.ReadLine();
}

First we retrieve the Movie we wish to delete. To do so we make use of the First extension method on the Linq query. The First method returns a single object rather than a collection. We then call the ObjectContext’s DeleteObject method passing it the Movie object we retrieved. At this point the ObjectStateManager has marked the object as having a “Deleted” state, though the Movie object has not been deleted from the model or the database. Calling the ObjectContext’s SaveChanges method detaches the Movie from the model and deletes the corresponding record from the database.

Here is the output:

--> The Princess Bride: Marked as Deleted in Model
Entity State: Deleted

--> The Princess Bride: Deleted from Model and Datasource
Entity State: Detached

Delete a Director object and its associated Movie objects using the Entity Framework

private static MovieEntities _entities = new MovieEntities();

static void Main(string[] args)
{
     Director spikeJonze = _entities.DirectorSet.
               Where(d => d.Name == "Spike Jonze").First();

     // Remember to Load associated objects
     spikeJonze.Movies.Load(); 

     Console.WriteLine("Number of Movies to Delete: {0}", 
               spikesMovies.Count());

     // Using ToList is also important
     foreach (var movie in spikeJonze.Movies.ToList())
     {
          _entities.DeleteObject(movie);
          Console.WriteLine("--> Movie {0}: 
                    Marked for Deletion", movie.Title);
     }

     _entities.DeleteObject(spikeJonze);
     Console.WriteLine("--> Director {0}: 
               Marked for Deletion", spikeJonze.Name);

     _entities.SaveChanges();
     Console.WriteLine("--> Director and 
               associated Movies Deleted");

     Console.ReadLine();
}

We retrieve the Director by passing a lambda expression to the Where extension method and use the First method to specify that we only want the first Movie object in the resulting collection. We then call the Load method on the Director’s Movies collection. This populates any Movies associated with the Director with values retrieved from the database. Each populated Movie object is added to the Movies collection. Neglecting to Load the Movies collection would result in an exception being thrown during the call to SaveChanges. This is because the Movies collection would appear to the ObjectContext to be empty, therefore, none of the Movies would be deleted. However, when SaveChanges is called, it would be determined that the Director does indeed have associated Movies in the database, and could therefore, not be deleted. Using the technique described in this example requires that objects must be loaded in order to be deleted.

Now that we have the Movies associated with the Director, we can loop over the collection and delete each Movie. Notice that the ToList extension method is called on the Director’s Movies collection. Doing so ensures that we are working with a separate instance of the Movies collection. If we tried to perform a delete operation on items in the actual collection we were iterating through, we would receive an error.

Once the Director’s Movies have been marked for deletion, we mark the Director for deletion as well. The subsequent call to the ObjectContext’s SaveChanges method results in the Director and his associated Movies being detached from the ObjectContext and deleted from the database.

Here is the output:

--> Number of Movies to Delete: 4

--> Movie Adaptation: Marked for Deletion
--> Movie Where the Wild Things Are: Marked for Deletion
--> Movie Human Nature: Marked for Deletion
--> Movie Being John Malkovich: Marked for Deletion

--> Director Spike Jonze: Marked for Deletion

--> Director and Associated Movies Deleted

Delete a Movie object without loading it using the Entity Framework

private static MovieEntities _entities = new MovieEntities();

static void Main(string[] args)
{
     int movieID = 105;
     int directorID = 2;
			
     Movie princessBride = new Movie();
     princessBride.ID = movieID;
     princessBride.DirectorReference.EntityKey = 
               new EntityKey("MovieEntities.DirectorSet", 
                         "ID", directorID);

     _entities.AttachTo("MovieEntities.MovieSet", 
               princessBride);
     _entities.DeleteObject(princessBride);
     _entities.SaveChanges();

     Console.ReadLine();
}

Assuming we know the ID of a Movie object, we can delete it without having to load it into the ObjectContext. We do so by creating a new Movie object, setting its ID property to the known value, and creating the EntityKeys for any EntityReferences the object may have. We then pass the Movie object to the ObjectContext’s AttachTo method, delete the object, and save the changes.

Unfortunately, I’ve not yet discovered a way to delete objects based on a property value, such as Movie.DirectorID, without loading the objects into the ObjectContext or performing a Linq query, both of which would require a call to the database. If you are aware of a method for doing so, please leave a comment and let us all know.

Exploring EntityStates when Deleting a Movie object using the Entity Framework

private static MovieEntities _entities = new MovieEntities();

static void Main(string[] args)
{
     Movie movieToDelete = 
          (from m in _entities.MovieSet
           where m.Title == "The Princess Bride"
	   select m).First();

     // Movie retrieved
     Console.WriteLine("--> {0}: Movie Retrieved", 
          movieToDelete.Title);
     Console.WriteLine("Entity State: {0}", 
          movieToDelete.EntityState); // Deleted

     EntityKey movieToDeleteKey = _entities.
          CreateEntityKey("MovieEntities.MovieSet", 
                                   movieToDelete);
     Console.WriteLine("Movie's EntityKey Value: {0}", 
          movieToDeleteKey.EntityKeyValues[0].Value);
     Console.WriteLine("DirectorReference 
          EntityKey is null: {0}", 
          movieToDelete.DirectorReference.EntityKey == null);
     Object deletedMovie = null;
     bool movieToDeleteExists = _entities.
          TryGetObjectByKey(movieToDeleteKey, 
               out deletedMovie);
     Console.WriteLine("Movie to Delete Exists
          in ObjectContext: {0}", 
          movieToDeleteExists);

     // Movie marked for deletion
     _entities.DeleteObject(movieToDelete);
     Console.WriteLine("\n\n--> {0}: Marked as Deleted in Model",
          movieToDelete.Title);
     Console.WriteLine("Entity State: {0}",
          movieToDelete.EntityState); // Deleted

     movieToDeleteKey = _entities.
          CreateEntityKey("MovieEntities.MovieSet", 
               movieToDelete);
     Console.WriteLine("Movie's EntityKey Value: {0}", 
          movieToDeleteKey.EntityKeyValues[0].Value);
     Console.WriteLine("DirectorReference 
          EntityKey is null: {0}", 
          movieToDelete.DirectorReference.EntityKey == null);
     deletedMovie = null; 
     movieToDeleteExists = _entities.
          TryGetObjectByKey(movieToDeleteKey, 
               out deletedMovie);
     Console.WriteLine("Movie to Delete Exists
          in ObjectConext: {0}", 
          movieToDeleteExists);


     // Movie detached from model and deleted from database
     _entities.SaveChanges();
     Console.WriteLine("\n\n--> {0}: 
          Deleted from Model and Datasource",
          movieToDelete.Title);
     Console.WriteLine("Entity State: {0}",
          movieToDelete.EntityState); // Detached

     movieToDeleteKey = _entities.
          CreateEntityKey("MovieEntities.MovieSet", 
               movieToDelete);
     Console.WriteLine("Movie's EntityKey Value: {0}", 
          movieToDeleteKey.EntityKeyValues[0].Value);
     Console.WriteLine("DirectorReference 
          EntityKey is null: {0}", 
          movieToDelete.DirectorReference.EntityKey == null);
     deletedMovie = null; 
     movieToDeleteExists = _entities.
          TryGetObjectByKey(movieToDeleteKey, 
               out deletedMovie);
     Console.WriteLine("Movie to Delete Exists
          in ObjectContext: {0}", 
          movieToDeleteExists);

     Console.ReadLine();
}

After marking the Movie for deletion, we are still able to make use of the object. In this case we grab the Movies EntityKey and make a call to the ObjectContext’s TryGetObjectByKey method. This method returns true if a Movie with the specified EntityKey exists in the model. It also creates a reference to the Movie and places it in the out parameter deletedMovie.

Calling the ObjectContext’s SaveChanges method detaches the Movie object from the model. The object retains its data values including its EntityKey, however, any relationships it might have had (such as the relationship used for the DirectorReference in this case) are lost. We are still able to retrieve the EntityKey from the detached object, however, the subsequent call to TryGetObjectByKey returns false because the Movie is no longer part of the ObjectContext.

Here is the output:

--> The Princess Bride: Movie Retrieved
Entity State: Unchanged
Movie's EntityKey Value: 97
DirectorReference EntityKey is null: False
Movie to Delete Exists in ObjectContext: True

--> The Princess Bride: Marked as Deleted in Model
Entity State: Deleted
Movie's EntityKey Value: 97
DirectorReference EntityKey is null: True
Movie to Delete Exists in ObjectContext: True

--> The Princess Bride: Deleted from Model and Datasource
Entity State: Detached
Movie's EntityKey Value: 97
DirectorReference EntityKey is null: True
Movie to Delete Exists in ObjectContext: False
Advertisements

One Response

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: