Saving Disconnected Entity in Entity Framework

Saving Disconnected Entity in Entity Framework

In this article, I am going to discuss how to work with the disconnected entities in Entity Framework. Please read our previous article where we discussed the Different Methods to Attach Disconnected Entities in Entity Framework. The Entities which are not tracked by the context object (DbContext object) are known as disconnected entities in Entity Framework and at the end of this article, you will learn how to insert, update and delete a disconnected entity in Entity Framework.

Note: We are going to work with the same example that we created in our Introduction to Entity Framework Database First Approach article. Please read our introduction to Entity Framework Database First article before proceeding to this article.

What are Disconnected Entities in Entity Framework?

In general, the DbContext instance automatically tracks the entities that are returned from the database, and any changes that we made to the entities are updated to the database when the SaveChanges method is called on the context object.

As discussed in our previous article, sometimes the entities are fetched or queried using one context object and then saved (or updated or deleted) using a different context object. In this case, the second context object needs to know whether the entities are new (should be inserted) or existing (should be updated or deleted) to the database.

How to save a disconnected entity in Entity Framework?

In Entity Framework, saving data in the disconnected scenario is different than saving data in the connected scenario. In a disconnected scenario, the context object (an instance of DbContext) is not aware of the entity’s state i.e. the entities were new or existing and such entities are called disconnected entities. In this case i.e. in the disconnected scenario, you need to attach the disconnected entities to the context object with appropriate EntityState in order to perform INSERT or UPDATE or DELETE operations in the database.

In Entity Framework Disconnected Scenario, it is your key responsibility to figure out whether the entity is a new one or an existing entity, and based on this, you need to set the appropriate entity state. Here, the important question is how you will figure out whether the entity is a new one or an existing one? For this, you need to check the key property value i.e. the Primary key value.

If the key property value is greater than zero, then it is an existing Entity and you can set the Entity State as Modified. On the other hand, if the key value is zero, then it is a new entity and you need to set the Entity State as Added. For better understanding, please have a look at the below diagram.

Working with Disconnected Entity in Entity Framework

Example: Saving a new entity in Entity Framework Disconnected Scenario

Please modify the Main method of the Program class as shown below. The following is an example of the Entity Framework Disconnected Scenario for adding a new entity.

using System;
using System.Data.Entity;
namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            //disconnected entity
            Student newDisconnectedStudent = new Student()
            {
                FirstName = "Steven",
                LastName = "Smith",
                StandardId = 1
            };

            using (var context = new EF_Demo_DBEntities())
            {
                context.Entry(newDisconnectedStudent).State = newDisconnectedStudent.StudentId == 0 ? EntityState.Added : EntityState.Modified;
                var studentEntry = context.Entry(newDisconnectedStudent);
                Console.WriteLine($"student Entity State: {studentEntry.State}");
                context.SaveChanges();
            }

            Console.Read();
        }
    }
}

In the above example, newDisconnectedStudent is a disconnected entity, and the context object is not aware of its state. The context.Entry(newDisconnectedStudent).State = student.StudentId == 0? EntityState.Added : EntityState.Modified; statement sets the entity state as Added if the value of the key property StudentId is zero, otherwise it sets the Modified state. In our example, the disconnected entity i.e. newDisconnectedStudent does not set the StudentId value so the default value is 0 and hence in this example, it will set the Entity State as Added and when you call the SaveChanges method it will execute the below SQL Statement in the database.

exec sp_executesql N’INSERT [dbo].[Student]([FirstName], [LastName], [StandardId])
VALUES (@0, @1, @2)
SELECT [StudentId]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentId] = scope_identity()’,N’@0 varchar(100),@1 varchar(100),@2 int’,@0=’Steven’,@1=’Smith’,@2=1

Example: Updating an existing entity in Entity Framework Disconnected Scenario

Please modify the Main method of the Program class as shown below. The following is an example of the Entity Framework Disconnected Scenario for updating an existing entity. In the below example, we set the value of StudentId property, and hence it will assign the entity State as the Modified state.

using System;
using System.Data.Entity;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            //disconnected entity
            Student newDisconnectedStudent = new Student()
            {
                StudentId = 1,
                FirstName = "FirstName Changed",
                StandardId = 2
            };

            using (var context = new EF_Demo_DBEntities())
            {
                context.Entry(newDisconnectedStudent).State = newDisconnectedStudent.StudentId == 0 ? EntityState.Added : EntityState.Modified;
                var studentEntry = context.Entry(newDisconnectedStudent);
                Console.WriteLine($"student Entity State: {studentEntry.State}");
                context.SaveChanges();
            }

            Console.Read();
        }
    }
}

When we execute the above program, the following UPDATE statement will execute in the database.

exec sp_executesql N’UPDATE [dbo].[Student]
SET [FirstName] = @0, [LastName] = NULL, [StandardId] = @1
WHERE ([StudentId] = @2)
‘,N’@0 varchar(100),@1 int,@2 int’,@0=’FirstName Changed’,@1=2,@2=1

Deleting a Disconnected Entity in Entity Framework:

Deleting a disconnected entity in Entity Framework is very simple. You just need to set its state to Delete using the Entry() method as shown in the below example.

using System;
using System.Data.Entity;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            //disconnected entity
            Student DisconnectedStudent = new Student()
            {
                StudentId = 7
            };

            using (var context = new EF_Demo_DBEntities())
            {
                context.Entry(DisconnectedStudent).State = EntityState.Deleted;
                var studentEntry = context.Entry(DisconnectedStudent);
                Console.WriteLine($"Entity State: {studentEntry.State}");
                context.SaveChanges();
            }

            Console.Read();
        }
    }
}

In the above example, the DisconnectedStudent instance contains only the StudentId key property. To delete an entity using the entity framework only requires the key property. context.Entry(DisconnectedStudent).State = System.Data.Entity.EntityState.Deleted attaches an entity to the context object and sets its state to Deleted. When you will execute the above example, the following DELETE statement is executed in the database.

exec sp_executesql N’DELETE [dbo].[Student]
WHERE ([StudentId] = @0)’,N’@0 int’,@0=7

Disconnected Entity Graph in Entity Framework

As of now, we understood how to save a disconnected entity in Entity Framework. Now let us move a step further and understand how to save a disconnected entity graph (an entity with its related entities) in the entity framework. While working with large applications or real-time applications, it is a common requirement to save or update one entity with its related entities. So, let us see how to do the same using the entity framework.

Note: The point that you need to remember is unlike the connected scenario, updating an entity graph in the disconnected scenario is a complex task. So, you need to do it carefully.

The problem in updating a disconnected entity graph is that the context object doesn’t know at the client-side what operation was performed on it. As a result, the new context object doesn’t know the state of each entity:

We need to identify the states of each entity in the entity graph before calling the SaveChages() method. There are different patterns that we can use to identify the state of each entity. In this demo, we are going to use the key property to identify the entity state.

Using Key Property

You can use the key (PrimaryKey) property of each entity to determine its state. The point that you need to consider is, if the value of the key property is the default value of CLR data type, then it is to be considered as a new entity else it is to be considered as an existing entity.

For example, if the data type of a key property is int and the value of the key property is zero, then it is a new entity. If a value is non-zero, then it is an existing entity. Similarly, if the key property is the string data type and if the value of the key property is null, then it is a new entity and if the value is not null, then it is an existing entity. For the new entity, the Entity Framework will execute the INSERT command while for the existing entity, the Entity Framework will execute the UPDATE command

The following example demonstrates saving the Student entity graph with the related Standard and Course entities:

using System;
using System.Collections.Generic;
using System.Data.Entity;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            var student = new Student()
            { 
                //Root entity (empty key)
                FirstName = "Steven",
                LastName = "Smith",
                Standard = new Standard()   //Child entity (with key value)
                {
                    StandardId = 1,
                    StandardName = "Standard 1"
                },
                Courses = new List<Course>() 
                {
                    new Course(){  CourseName = "AI" }, //Child entity (empty key)
                    new Course(){  CourseId = 2 } //Child entity (with key value)
                }
            };

            using (var context = new EF_Demo_DBEntities())
            {
                //Set the Student entity state based on StudentId
                context.Entry(student).State = student.StudentId == 0 ? EntityState.Added : EntityState.Modified;

                //Set the Standard entity state based on StandardId
                context.Entry(student.Standard).State = student.Standard.StandardId == 0 ? EntityState.Added : EntityState.Modified;

                //Set the Course entity state based on CourseId
                foreach (var course in student.Courses)
                {
                    context.Entry(course).State = course.CourseId == 0 ? EntityState.Added : EntityState.Modified;
                }
                  
                context.SaveChanges();
            }

            Console.Read();
        }
    }
}

In the above example, the student entity graph includes the related Standard and Course entities. The context sets an appropriate state for each entity based on the key property value. If it is zero, then it sets the Added state, otherwise, it sets the Modified state. The SaveChanges() method will execute the appropriate INSERT or UPDATE command to the database for each entity.

In the next article, I am going to discuss Asynchronous Programming using Entity Framework. Here, in this article, I try to explain How to work with Disconnected Entity in Entity Framework and I hope you enjoyed this Disconnected Entity in Entity Framework article. Please give your valuable feedback and suggestions about this article.

Leave a Reply

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