Back to: ASP.NET Core Tutorials For Beginners and Professionals
Entity States in Entity Framework Core (EF Core)
In this article, I am going to discuss Entity States in Entity Framework Core (EF Core). Please read our previous article, where we discussed CRUD Operations in Entity Framework Core. We will work with the same example we have worked on so far.
Entity States in Entity Framework Core (EF Core)
The Entity Lifecycle in Entity Framework Core describes the process in which an Entity is created, added, modified, deleted, etc. Entities have many states during their lifetime. EF Core maintains the state of each entity during its lifetime. Each entity has a state based on the operation performed on it via the context class (the class which is derived from DbContext class). The entity state is represented by an enum called EntityState in EF Core with the following signature.
That means the Entity State represents the state of an entity. An entity is always in any one of the following states.
- Added: The entity is being tracked by the context but does not yet exist in the database.
- Deleted: The entity is being tracked by the context and exists in the database. It has been marked for deletion from the database.
- Modified: The entity is being tracked by the context and exists in the database. Some or all of its property values have been modified.
- Unchanged: The entity is being tracked by the context and exists in the database. Its property values have not changed from the values in the database.
- Detached: The entity is not being tracked by the context.
The Context object not only holds the reference to all the entity objects as soon as retrieved from the database but also keeps track of entity states and maintains modifications made to the properties of the entity. This feature is known as Change Tracking.
Entity Lifecycle in Entity Framework Core
The change in the entity state from the Unchanged to the Modified state is the only state that’s automatically handled by the context class. All other changes must be made explicitly using the proper DbContext class methods. The following diagram shows the different states of an entity in the Entity Framework.
Added State of an Entity in EF Core with Example
Whenever we add a new Entity to the context object using the Add method of DbSet or DbContext, then the state of the entity will be in the Added state. Added entity state indicates that the entity exists in the context but does not exist in the database.
In this case, DbContext generates the INSERT SQL Statement and inserts the data into the database when the SaveChanges method is invoked. Once the SaveChanges method execution is successful, the state of the Entity is changed from Added to Unchanged state.
For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create a new student which you want to add to the database var newStudent = new Student() { FirstName = "Pranaya", LastName = "Rout", DateOfBirth = new DateTime(1988, 02, 29), Height = 5.10m, Weight = 72 }; //Create DBContext object using var context = new EFCoreDbContext(); //Add Student Entity into Context Object context.Students.Add(newStudent); //context.Add<Student>(newStudent); //context.Add(newStudent); //Now the Entity State will be in Added State Console.WriteLine($"Before SaveChanges Entity State: {context.Entry(newStudent).State}"); //Call SaveChanges method to save student entity into database context.SaveChanges(); //Now the Entity State will change from Added State to Unchanged State Console.WriteLine($"After SaveChanges Entity State: {context.Entry(newStudent).State}"); Console.WriteLine("Student Saved Successfully..."); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
If you verify the database, you will see the above entity is being added to the Students database table, as shown below. Please note Student ID, which we will use in our next examples.
Unchanged State of an Entity in Entity Framework with Example
The entity’s property values have not been modified since it was retrieved from the database. SaveChanges ignores this entity. This is the default state the entities will be in when we perform the query and when we attach an entity to the context using the Attach() method.
using EFCoreCodeFirstDemo.Entities; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); var student = context.Students.Find(2); if (student != null) { //Check the Entity State Before Modifying Console.WriteLine($"Before SaveChanges Entity State: {context.Entry(student).State}"); //Calling SaveChanges Doesnot Do Anything context.SaveChanges(); //Check the Entity State After Calling the SaveChanges Method of Context Object Console.WriteLine($"After SaveChanges Entity State: {context.Entry(student).State}"); } else { Console.WriteLine("Student Not Exists"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
Attaching an Existing Entity to the Context
If you have an entity that already exists in the database but is not currently being tracked by the context, then you can tell the context to track the entity using the Attach method on DbSet or DbContext object. The entity will be in the Unchanged state in the context.
For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; using Microsoft.EntityFrameworkCore; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); //Create an Existing student which you want to add to the database var existingStudent = new Student() { StudentId = 2, FirstName = "Pranaya", LastName = "Rout", DateOfBirth = new DateTime(1988, 02, 29), Height = 5.10m, Weight = 72 }; //Attaching the Entity to the Context context.Students.Attach(existingStudent); //context.Attach<Student>(existingStudent); //context.Attach(existingStudent); //Or you can also attach an existing entity as follows by updating the entity state //context.Entry(existingStudent).State = EntityState.Unchanged; //Check the Entity State Before SaveChanges Console.WriteLine($"Before SaveChanges Entity State: {context.Entry(existingStudent).State}"); context.SaveChanges(); //Check the Entity State After Calling the SaveChanges Method of Context Object Console.WriteLine($"After SaveChanges Entity State: {context.Entry(existingStudent).State}"); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
Attaching a New Entity to the Context
If you have a new entity and if you attach the entity to the context object using the DbSet or DbContext attach method, then the context object will track the entity with Added only, not Unchanged state. Once you call the SaveChanges method, it will add the entity to the database and change the state from Added to Unchanged.
For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; using Microsoft.EntityFrameworkCore; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); //Create an Existing student which you want to add to the database var existingStudent = new Student() { FirstName = "Rakesh", LastName = "Kumar", DateOfBirth = new DateTime(1988, 02, 29), Height = 5.10m, Weight = 72 }; //Attaching the Entity to the Context context.Students.Attach(existingStudent); //context.Attach<Student>(existingStudent); //context.Attach(existingStudent); //Or you can also attach an existing entity as follows by updating the entity state //context.Entry(existingStudent).State = EntityState.Unchanged; //Check the Entity State Before SaveChanges Console.WriteLine($"Before SaveChanges Entity State: {context.Entry(existingStudent).State}"); context.SaveChanges(); //Check the Entity State After Calling the SaveChanges Method of Context Object Console.WriteLine($"After SaveChanges Entity State: {context.Entry(existingStudent).State}"); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
Detached State of an Entity in Entity Framework Core with Example
We can change the Entity State to the Detached state by using the Entity State property. Once the entity is in the Detached state, it can no longer be tracked by the Context object. Later, if you want, then again, you have to use the Attach() method for the entity to be tracked by the Context. The Detached entity state indicates that the context is not tracking the entity.
For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; using Microsoft.EntityFrameworkCore; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); //Fetch the Student whose ID = 2 var student = context.Students.Find(2); if (student != null) { //Check the Entity State Before Modifying Console.WriteLine($"Before Detached Entity State: {context.Entry(student).State}"); //Changing the Entity State to Detached context.Entry(student).State = EntityState.Detached; Console.WriteLine($"Entity State After Detached: {context.Entry(student).State}"); //Change of the Property //The following changes will have no impact on the database student.LastName = "LastName Changed"; //SaveChanges will not do anything with Detached state Entity context.SaveChanges(); //Check the Entity State After Calling the SaveChanges Method of Context Object Console.WriteLine($"After SaveChanges Entity State: {context.Entry(student).State}"); } else { Console.WriteLine("Student Not Exists"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
Modified State in Entity Framework Core (EF Core) with Example
The entity will be in a Modified state whenever we modify scalar properties. The Modified entity state indicates that the entity is modified but not updated in the database. It also indicates that the entity exists in the database. The DbContext generates the UPDATE SQL Statement to update the entity in the database. Once the SaveChanges is successful, then the state of the entity is changed to Unchanged. For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; using Microsoft.EntityFrameworkCore; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); //Fetch the Student whose ID = 2 var student = context.Students.Find(2); if (student != null) { Console.WriteLine($"Before Modifying Entity State: {context.Entry(student).State}"); //Modify the Entity student.FirstName = "FirstName Changed"; Console.WriteLine($"After Modifying Entity State: {context.Entry(student).State}"); //Update the Entity in the Database by calling the SaveChanges Method context.SaveChanges(); Console.WriteLine($"After SaveChanges Entity State: {context.Entry(student).State}"); } else { Console.WriteLine("Student Not Exists"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
Note: The Entity framework keeps track of the properties that have been modified. The Columns in the Update statement are set for only those columns whose values are modified.
Deleted State in EF Core with Example
Whenever we call the Remove method, the entity will be removed from the context and will be marked as a “Deleted” state. When the SaveChanges method is called, the corresponding row is deleted from the database.
The Deleted entity state indicates that the entity is marked for deletion but not yet deleted from the database. It also indicates that the entity exists in the database. The DbContext generates the DELETE SQL Query to remove the entity from the database. The entity is removed from the context once the delete operation succeeds after the SaveChanges.
For a better understanding, please have a look at the following example. The following example code is self-explained, so please go through the comment line.
using EFCoreCodeFirstDemo.Entities; using Microsoft.EntityFrameworkCore; namespace EFCoreCodeFirstDemo { public class Program { static void Main(string[] args) { try { //Create DBContext object using var context = new EFCoreDbContext(); //Fetch the Student whose ID = 2 var student = context.Students.Find(2); if (student != null) { Console.WriteLine($"Before DELETING Entity State: {context.Entry(student).State}"); //Remove the Entity context.Students.Remove(student); //context.Remove<Student>(student); //context.Remove(student); Console.WriteLine($"After DELETING Entity State: {context.Entry(student).State}"); //Delete the Entity in the Database by calling the SaveChanges Method context.SaveChanges(); Console.WriteLine($"After SaveChanges Entity State: {context.Entry(student).State}"); } else { Console.WriteLine("Student Not Exists"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); ; } Console.ReadKey(); } } }
Output:
What SaveChanges Method Does in Entity Framework Core?
The SaveChanges method of context object does different things for entities in different states. They are as follows:
- If the entities are in an Unchanged State, then the SaveChanges method will not touch them. And this makes sense because the entities are not modified, added, or deleted. Then why should they be sent to the database?
- If the entities are in Added State, then those entities are inserted into the database when the SaveChanges method is called by generating and executing the INSERT SQL Statement, and once the SaveChanges method is called, then those entities are moved to the Unchanged state.
- If the entities are in Modified State, then those entities are updated in the database when the SaveChanges method is called by generating and executing the UPDATE SQL Statement, and once the SaveChanges method is called, then those entities are moved to Unchanged state.
- If the entities are in Deleted State, then those entities are deleted from the database when the SaveChanges method is called by generating and executing the DELETE SQL Statement, and then, they are detached from the context object, i.e., their state is not maintained by the context object anymore.
Note: The point that you need to remember is Entity Framework builds and executes the INSERT, UPDATE, and DELETE commands based on the state of an entity when the SaveChanges() method is called. It generates and executes the INSERT command for the entities with Added state, generates and executes the UPDATE command for the entities with the Modified state, and generates and executes the DELETE command for the entities in the Deleted state.
In the next article, I am going to discuss LINQ to Entities in Entity Framework Core. In this article, I try to explain CRUD Operations in Entity Framework Core. I hope you enjoy this CRUD Operations in Entity Framework Core article.