Using the Entity Framework: Update Operation (Quick Reference)

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

This quick reference is for those who are using the Entity Framework and want examples of how to perform everyday CRUD tasks. We’ll take a look at how to update 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.

Update a Director object 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();

     spikeJonze.Name = "Adam Spiegel a.k.a \"Spike Jonze\"";
     _entities.SaveChanges();

     Console.ReadLine();
}

First, we retrieve a Director object by specifying a value for the Name property in a lambda expression. Next, we update the Director’s Name property. Finally, we call the ObjectContext’s SaveChanges method to commit the changes to the model and the database.

Using the ObjectStateManager when Updating a Director object 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();

     spikeJonze.Name = "Adam Spiegel a.k.a \"Spike Jonze\"";

     ObjectStateEntry entry = _entities.ObjectStateManager.
               GetObjectStateEntry(spikeJonze.EntityKey);
     IEnumerable<string$gt; modProps = entry.
               GetModifiedProperties();

     foreach (string prop in modProps)
     {
          Console.WriteLine("Modified Property: {0}", 
                    prop.ToString());

          Console.WriteLine("IsDbNull: {0}", 
                    entry.OriginalValues.
                    IsDBNull(
                         entry.OriginalValues.GetOrdinal(prop)
                    )
          );

          Console.WriteLine("Changed from: {0}", 
                    entry.OriginalValues[prop]);

          Console.WriteLine("Changed to: {0}", 
                    entry.CurrentValues[prop]);
     }

     Console.WriteLine("Entity State: {0}", entry.State);

     Console.WriteLine("\n--> All Original Values");
     for (int i = 0; i < entry.OriginalValues.FieldCount; i++)
     {
          Console.WriteLine("{0}: {1}", 
                    entry.OriginalValues.GetName(i), 
                    entry.OriginalValues[i]);
     }

     _entities.SaveChanges();

     Console.ReadLine();
}

After modifying a property an object, we can use the ObjectStateManager to access state information such as, which properties were modified, those properties original values, their current values, and other helpful information.

To access this information we call the ObjectContext’s GetObjectStateEntry method passing in the Director’s EntityKey. This method returns the ObjectStateEntry for the specified Director object. To determine which properties have been modified, we call the ObjectStateEntries GetModifiedProperties method which returns a collection of the names of any properties whose current values are different from their original values.

To determine the original value of a property, we retrieve the value at a given index in the ObjectStateEntry’s OriginalValues collection. Since OriginalValues is an indexed collection we can specify either the number of the database column or the name of the column (or property) as such, entry.OriginalValues["name"]. We then use the CurrentValues collection to retrieve the current value of the modified property.

Lastly, for the purpose of illustration, we loop over the OriginalValues collection and output all of the Director object’s property names and their respective values.

Here is the output:

Modified Property: Name
IsDbNull: False
Changed from: Spike Jonze
Changed to: Adam Spiegel a.k.a "Spike Jonze"
Entity State: Modified

--> All Original Values
ID: 33
Name: Spike Jonze
Hometown: Rockville Maryland
Birthday: 10/22/1969
Advertisements

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