Entity States in Entity Framework Core

Entity States in Entity Framework Core (EF Core)

In this article, I will discuss Entity States in Entity Framework Core (EF Core). Please read our previous article discussing 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 how 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 via the context class (the class derived from the DbContext class).

Each entity tracked by the DbContext has a state, which indicates how the entity should be processed during a SaveChanges() operation. 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)

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 tracked by the context but does not yet exist in the database.
  2. Deleted: The entity is tracked by the context and exists in the database. It has been marked for deletion from the database but has not yet been deleted.
  3. Modified: The entity is tracked by the context and exists in the database. Some or all of its property values have been modified but not updated in the database.
  4. Unchanged: The entity is tracked by the context and exists in the database. Its property values have not changed from those 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 to the entity’s properties. This feature is known as Change Tracking.

What is Change Tracking?

Entity Framework Core (EF Core) uses the concept called change tracking to determine what operations (like insert, update, or delete) should be executed when the SaveChanges() method is called. It uses something called “Entity States” to determine what operations to be done. Each entity tracked by the DbContext has a state, which indicates how the entity should be processed during a SaveChanges() operation.

Entity Lifecycle in Entity Framework Core

When working with Entity Framework Core (EF Core), it’s important to understand the entity lifecycle clearly. The entity lifecycle involves different states and transitions that determine how entities interact with the DbContext and, ultimately, to the database. Understanding the Entity lifecycle is crucial for maintaining data integrity in your applications.

The change in the entity state from the Unchanged to the Modified state is the only state 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 the 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

Once we retrieve the entity from the database, it will be in the UnChanged state as long as we haven’t modified the entity’s property. When we call theSaveChanges, it ignores this entity. This is the default state the entities will be in when we perform the query and 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:

blank

Attaching an Existing Entity to the Context Object:

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 the 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 state only, not Unchanged state. Once you call the SaveChanges method, It will insert that entity into 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 will 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 the scalar properties of an entity. The Modified state of an entity 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, the entity’s state is changed from Modified 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

The entity will be removed from the context and marked as a “Deleted” state whenever we call the Remove method. 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 statement 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 the 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. 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 the 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 execution is successful, then those entities are moved from Added 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. Once the SaveChanges method execution is successful, those entities are moved from Modified to Unchanged.
  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. Then, they are detached from the context object, i.e., their state is no longer maintained by the context object.

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 the 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 will 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 *