Entity States in Entity Framework Core

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.

Entity States in Entity Framework Core (EF Core)

That means the Entity State represents the state of an entity. An entity is always in any one of the following states.

  1. Added: The entity is being tracked by the context but does not yet exist in the database.
  2. Deleted: The entity is being tracked by the context and exists in the database. It has been marked for deletion from the database.
  3. Modified: The entity is being tracked by the context and exists in the database. Some or all of its property values have been modified.
  4. 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.
  5. 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.

Entity Lifecycle in Entity Framework Core

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:

Added State of an Entity in EF Core with Example

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.

Added State of an Entity in EF Core with Example

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 an Existing Entity to the Context

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:

Attaching a New Entity to the Context

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:

Detached State of an Entity in Entity Framework Core with Example

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:

Modified State in Entity Framework Core (EF Core) with Example

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:

Deleted State in EF Core with Example

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:

  1. 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?
  2. 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.
  3. 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.
  4. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *