DbContext in Entity Framework

DbContext in Entity Framework Database First Approach

In this article, I am going to discuss DbContext class in Entity Framework Database First Approach. Please read our previous article where we discussed Model Browser in Entity Framework. At the end of this article, you will understand the need and use of the Entity Framework DbContext class in detail.

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.

Entity Framework DbContext Class:

Whenever we use Entity Framework Database First Approach to interact with an existing database, then the EDM (Entity Data Model) creates a class called DbContext for us. Every Entity Data Model (EDM) generates one context class for the database. In order to verify this, expand the .edmx file in the solution explorer and open <EDM Name>.Context.tt as shown in the below image. In our example, it will be StudentDataModel.Context.tt.

DbContext in Entity Framework Database First Approach

StudentDataModel.Context.tt: 

This T4 template file generates a context class whenever you change the Entity Data Model (.edmx file). You can see the context class file by expanding StudentDataModel.Context.tt. The context class resides in the <EDM Name>.context.cs file. In our case the context class file name is StudentDataModel.Context.cs. The default context class name is <DB Name>Entities. For example, the context class name for EF_Demo_DB is EF_Demo_DBEntities and derived from the DBContext class as shown below.

StudentDataModel.Context.tt: 

Note: The class that is derived from the System.Data.Entity.DbContext class is called a context class in the entity framework.

What are the responsibilities of DbContext class in Entity Framework?

The DbContext class in Entity Framework is an important class and is primarily responsible for interacting with data as objects. It acts as a bridge between your domain classes or entity classes and the underlying relational database. For better understanding, please have a look at the following image.

What are the responsibilities of DbContext class in Entity Framework?

Let us understand what are the responsibilities done by DbContext class in the Entity Framework. The DbContext class is responsible for the following activities in Entity Framework:

  1. Querying: Mostly when we are working with Entity Framework, we used Linq Queries. The DbContext class is responsible for converting the LINQ-to-Entities queries to SQL query which is understood by the underlying database and then sends them to the database.
  2. Change Tracking: In our Entity States in Entity Framework article we discussed the different states of an Entity and it is also possible to change the state from one state to another. The Entity Framework DbContext class is also responsible for keeps track of changes that occurred on the entities after querying from the database.
  3. Persisting Data: The DbContext class is also responsible for performs the Insert, Update and Delete operations to the database which is persistent data permanently to the database.
  4. Caching: Nowadays caching plays an important role in almost all types of applications to improve performance. By default, the DbContext class provides the first-level cache. That means it stores the entities which have been retrieved from the database during the lifetime of a context class.
  5. Manage Relationship: It Manages the relationships among the entities using CSDL, MSL, and SSDL in Db-First or Model-First approach, and using fluent API configurations in the Code-First approach.
  6. Object Materialization: The DbContext is responsible for converting the raw data retrieved from the database into entity objects in Entity Framework.

Note: If you are not understanding the above points then don’t worry, we will discuss the above points in detail with examples in our upcoming article.

DbContext class:

The following is an example of EF_Demo_DBEntities class (context class that derives from DbContext) generated with EDM for the EF_Demo_DB database in the previous article.

namespace DBFirstApproach
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.Core.Objects;
    using System.Linq;
    
    public partial class EF_Demo_DBEntities : DbContext
    {
        public EF_Demo_DBEntities()
            : base("name=EF_Demo_DBEntities")
        {
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
    
        public virtual DbSet<Course> Courses { get; set; }
        public virtual DbSet<Standard> Standards { get; set; }
        public virtual DbSet<Student> Students { get; set; }
        public virtual DbSet<StudentAddress> StudentAddresses { get; set; }
        public virtual DbSet<Teacher> Teachers { get; set; }
        public virtual DbSet<vwStudentCourse> vwStudentCourses { get; set; }
    
        public virtual int spDeleteStudent(Nullable<int> studentId)
        {
            var studentIdParameter = studentId.HasValue ?
                new ObjectParameter("StudentId", studentId) :
                new ObjectParameter("StudentId", typeof(int));
    
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("spDeleteStudent", studentIdParameter);
        }    
        public virtual ObjectResult<spGetCoursesByStudentId_Result> spGetCoursesByStudentId(Nullable<int> studentID)
        {
            var studentIDParameter = studentID.HasValue ?
                new ObjectParameter("StudentID", studentID) :
                new ObjectParameter("StudentID", typeof(int));
    
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<spGetCoursesByStudentId_Result>("spGetCoursesByStudentId", studentIDParameter);
        }   
        public virtual ObjectResult<Nullable<decimal>> spInsertStudent(Nullable<int> standardId, string firstName, string lastName)
        {
            var standardIdParameter = standardId.HasValue ?
                new ObjectParameter("StandardId", standardId) :
                new ObjectParameter("StandardId", typeof(int));
    
            var firstNameParameter = firstName != null ?
                new ObjectParameter("FirstName", firstName) :
                new ObjectParameter("FirstName", typeof(string));
    
            var lastNameParameter = lastName != null ?
                new ObjectParameter("LastName", lastName) :
                new ObjectParameter("LastName", typeof(string));
    
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<decimal>>("spInsertStudent", standardIdParameter, firstNameParameter, lastNameParameter);
        }
        public virtual int spUpdateStudent(Nullable<int> studentId, Nullable<int> standardId, string firstName, string lastName)
        {
            var studentIdParameter = studentId.HasValue ?
                new ObjectParameter("StudentId", studentId) :
                new ObjectParameter("StudentId", typeof(int));
    
            var standardIdParameter = standardId.HasValue ?
                new ObjectParameter("StandardId", standardId) :
                new ObjectParameter("StandardId", typeof(int));
    
            var firstNameParameter = firstName != null ?
                new ObjectParameter("FirstName", firstName) :
                new ObjectParameter("FirstName", typeof(string));
    
            var lastNameParameter = lastName != null ?
                new ObjectParameter("LastName", lastName) :
                new ObjectParameter("LastName", typeof(string));
    
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("spUpdateStudent", studentIdParameter, standardIdParameter, firstNameParameter, lastNameParameter);
        }
    }
}

As you can see in the above code, the context class (EF_Demo_DBEntities) includes the entity set of type DbSet<TEntity> for all the tables and views. In our next article, we will discuss the DbSet class in detail. It also includes functions for the stored procedures and functions. In our example, we don’t have any functions but we have stored procedures and for each stored procedure its creates separate functions. The OnModelCreating method allows us to configure the model using the DbModelBuilder Fluent API in Entity Framework.

DbContext Methods
  1. Entry: Gets a DbEntityEntry for the given entity. The entry provides access to change tracking information and operations for the entity.
  2. SaveChanges: Executes INSERT, UPDATE, and DELETE commands to the database for the entities with Added, Modified, and Deleted states.
  3. SaveChangesAsync: Asynchronous method of SaveChanges()
  4. Set: Creates a DbSet<TEntity> that can be used to query and save instances of TEntity.
  5. OnModelCreating: Override this method to further configure the model that was discovered by convention from the entity types exposed in DbSet<TEntity> properties on your derived context.
DbContext Properties
  1. ChangeTracker: Provides access to information and operations for entity instances that this context is tracking.
  2. Configuration: Provides access to configuration options.
  3. Database: Provides access to database-related information and operations.
Example:

Using DbContext class we can perform the CRUD operation. Let us perform the four operations using DbContext class.

Adding New Entity in Entity Framework Database First Approach:

Now, we need to add one entity i.e. one Student into the Student table. Adding a new object with the Entity Framework is very simple. Just create an instance of the entity and then register it using the Add method on DbSet and call the SaveChanges method. The following piece of code in the main method does the same. So, please modify the main method of the Program class as shown below.

using System;
using System.Collections.Generic;
using System.Linq;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EF_Demo_DBEntities context = new EF_Demo_DBEntities())
            {
                //Adding new student
                var student = new Student
                {
                    FirstName = "Hina",
                    LastName = "Sharma",
                    StandardId = 1
                };

                context.Students.Add(student);
                context.SaveChanges();

                //Verifying the new student
                List<Student> listStudents = context.Students.ToList();
                foreach (Student std in listStudents)
                {
                    Console.WriteLine($"StudentID: {std.StudentId} Name = {std.FirstName} {std.LastName}");
                }
                Console.ReadKey();

            }
        }
    }
}

Output: You can see the newly added student in the console window and you can also verify the same in the Student table of the EF_Demo_DB database.

Adding New Entity in Entity Framework

Updating Existing Entities in Entity Framework Database First Approach

Now, we need to update one entity i.e. we need to update the First name and Last name of the newly created student i.e. the student whose student id is 5. The following piece of code in the main method exactly does the same. So, please modify the main method of the Program class as shown below.

using System;
using System.Collections.Generic;
using System.Linq;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EF_Demo_DBEntities context = new EF_Demo_DBEntities())
            {
                //First fetch the student data
                var student = context.Students.FirstOrDefault(x => x.StudentId == 5);

                //if the student exists then modify the data'
                if (student != null)
                {
                    student.FirstName = "Hina1";
                    student.LastName = "Sharma1";
                    context.SaveChanges();
                }

                //Verifying the updated data
                List<Student> listStudents = context.Students.ToList();
                foreach (Student std in listStudents)
                {
                    Console.WriteLine($"StudentID: {std.StudentId} Name = {std.FirstName} {std.LastName}");
                }
                Console.ReadKey();
            }
        }
    }
}

Output: You can see the updated data in the console window and you can also verify the same in the Student table of the EF_Demo_DB database.

Updating Existing Entities in Entity Framework Database First Approach

Deleting an Entity in Entity Framework Database First Approach

Now, we need to delete the newly created entity i.e. the student whose student id is 5. To delete an entity using Entity Framework, we need to use the Remove method on DbSet. The Remove method works for both existing and newly added entities. Calling Remove on an entity that has been added but not yet saved to the database will cancel the addition of the entity. The entity is removed from the change tracker and is no longer tracked by the DbContext. Calling Remove on an existing entity that is being change-tracked will register the entity for deletion the next time SaveChanges is called. The following example shows an instance where the student is removed from the database whose id is 5.

using System;
using System.Collections.Generic;
using System.Linq;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EF_Demo_DBEntities context = new EF_Demo_DBEntities())
            {
                //First fetch the student data
                var student = context.Students.FirstOrDefault(x => x.StudentId == 5);

                //if the student exists then remove
                if (student != null)
                {
                    context.Students.Remove(student);
                    context.SaveChanges();
                }

                //Verifying the updated data
                List<Student> listStudents = context.Students.ToList();
                foreach (Student std in listStudents)
                {
                    Console.WriteLine($"StudentID: {std.StudentId} Name = {std.FirstName} {std.LastName}");
                }
                Console.ReadKey();
            }
        }
    }
}

Output: Now, you can observe the deleted data not showing in the Console. You can also verify the same in the Student table of the EF_Demo_DB database.

Deleting an Entity in Entity Framework Database First Approach

Points to Remember:
  1. DbContext API is mostly targeted at simplifying your interaction with Entity Framework.
  2. It also reduces the number of methods and properties you need to access commonly used tasks.
  3. The context class manages the entity objects during run time, which includes populating objects with data from a database, change tracking, and persisting data to the database.

In the next article, I am going to discuss the DbSet in Entity Framework. In this article, I try to explain the DbContext class in Entity Framework Database First Approach and I hope you enjoyed DbContext class in the 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 *