DbContext is the most important part of Entity Framework. There are many articles on Entity Framework and very small information on DbContext in a single place. In this article, I am trying to explain all aspects of DbContext and why it is the most important class in Entity Framework.
What is DbContext?
The simple answer to this question DbContext is the CLASS in Entity Framework/Core.
As per Microsoft “A DbContext instance represents a session with the database and can be used to query and save instances of your entities. DbContext is a combination of the Unit Of Work and Repository patterns.” In simplified way we can say that DbContext is the bridge between Entity Framework and Database. Whatever we are doing in Entity Framework (get data, save data, fetch data or any other opration) is done via DbContext.
What we can do with DbContext?
This is the next question. I am trying to answer or discuss one by one now.
Manage database connection
As we know Entity Framework is build upon ADO.NET so EF also manage a Connection Pool. DbContext open the connection whenever needed at the time of communication with Database. Many times multiple operation done by single connection and vice versa. As it is managing the Connection pool we need not to worry about the connections. This is the beauty of entity Framework.
Configure model & relationship
Basically Model is a class that represent database table, stored procedure, function and so on. We can create manually this class and configure it in DbContext like below or we can create all models of all or specific objects from Database.
public class Post
{
public int PostId { get; set; }
public string Url { get; set; }
}
//Mention it in DbContext class like below
public DbSet< Post > Posts { get; set; }
//Configure model like below
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>() .Property(b => b.Url) .IsRequired();
}
//Or we can use data annotation like below. [Required] in this case
public class Post
{
public int PostId { get; set; }
[Required]
public string Url { get; set; }
}
Query the database
Another advantage or feature of DBContext is we can query database using different approaches like using entities, stored procedures or even executing queries directly. few examples are as below
- Using entity - Here we can use single model for crud operation. if we need data of few columns from multiple tables, we can fetch as below
objData = (from c in context.TblDiscussion
join ct in context.TblCallTypes on c.CallType equals ct.Id
join cld in context.LoginDetails on c.AddedBy equals cld.LoginId
where c.GroupId == GroupId
select new DiscussionDetails
{
Id = c.Id,
AddedDate = c.AddedDate,
SpokenTo = c.SpokenTo,
ContactNo = c.ContactNo,
CallType = ct.CallType,
CustomerType = c.CustomerType,
FollowupDate = c.FollowupDate,
AddedBy = cld.UserName,
Status = c.Status,
}).OrderByDescending(x => x.AddedDate).ToList();
- Using Stored Procedure - With this approach we can call stored procedure and get data. if selecting data in SP we can get the data in model or list of model like below
List<ForGraph> lstData = new List<ForGraph>();
using (var context = new CommonDBContext())
{
lstData = context.Database.SqlQuery<ForGraph>("sp_GetDataForGraph @type, @CSMember",
new SqlParameter("@type", type),
new SqlParameter("@CSMember", CSMember)).ToList<ForGraph>();
}
- Execute normal query - We can execute query directly.
using (var contextdb = new CommonDBContext(connStr))
{
var sqlQ = $"SELECT COUNT(*) as Count FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName'";
var exist = contextdb.Database.SqlQuery<int>(sqlQ).FirstOrDefault();
}
Tracking changes
This is the most important feature of DBContext. we can track changes when we use for all type of operations or execution.
using (var context = new CommonDBEntities()) {
//Below line enable tracking for all operation inside this block, as object context gets disposed
context.Configuration.AutoDetectChangesEnabled = true;
var student = (from stud in context.tblStudents where stud.Name ==
"Dinesh" select stud).FirstOrDefault<Student>();
//here we can check how many entities get affected
context.ChangeTracker.Entries().Count();
//If you want to check each entity that gets affected you can use below code
var affectedEntities = context.ChangeTracker.Entries();
foreach (var entity in affectedEntities) {
// Here we can get name of entity
Console.WriteLine("Affected Entity Name: {0}", entity.Entity.GetType().Name);
// Here we can check state
Console.WriteLine("Status Affected: {0}", entity.State);
}
}
Managing Transaction
Transaction is very useful feature while working with Database(specially Relational Databases). When data gets inserted in multiple tables on single event the Transaction plays critical role to avoid data discrepancy. DBContext use transactions internally for individual operation and exactly it is the problem when we insert or update or delete data in multiple database tables. In these cases we can use Transaction explecitely as below
using (var context = new CommonDBContext())
{
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
context.tblStudents.AddOrUpdate(objStudent);
context.SaveChanges();
context.tblStudentsSalaryDetails.AddOrUpdate(objStudentSalary);
context.SaveChanges();
context.tblStudentsFamilyDetails.AddOrUpdate(objStudentFamily);
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
//Log Exception
}
}
}
In above code if all Insert/Update statements executed correctly without error the transaction gets commited and all data gets stored/updated successfully. if not means if any error occurs in any statement all inserted or updated data gets rollback. This way we can use transaction to avoid data discrepancy
__Happy Coding__