DbContext and DbSet in Entity Framework

Entity Framework (EF) Core provides powerful abstractions for interacting with databases in .NET applications. At the core of this interaction are two fundamental classes: DbContext and DbSet<TEntity>. Understanding their roles is crucial for effective data management.

The Role of DbContext

The DbContext class is the primary gateway to your data in Entity Framework. It represents a session with the database and is the entry point for querying and saving data. Key responsibilities of DbContext include:

Creating a DbContext

Typically, you create a custom class that inherits from DbContext and exposes properties of type DbSet<TEntity> for each entity in your model. This class is then configured using methods like OnConfiguring or by using dependency injection.

Example: Custom DbContext


using Microsoft.EntityFrameworkCore;

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    // Constructor or configuration methods would go here
    // For example, using OnConfiguring:
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public virtual ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}
            

The Role of DbSet<TEntity>

A DbSet<TEntity> represents a collection of all entities of a given type in the context. It's analogous to a table in a relational database. Through a DbSet, you can perform LINQ queries against the database and add, remove, or modify entities.

Key Point:

The DbSet<TEntity> itself does not perform database operations immediately. It prepares the operations, and they are executed when DbContext.SaveChanges() is called.

Common Operations with DbContext and DbSet

Querying Data

You can query data using LINQ methods directly on your DbSet properties within your DbContext instance.

Example: Querying Blogs


using (var context = new BloggingContext())
{
    // Get all blogs
    var allBlogs = context.Blogs.ToList();

    // Get blogs with a specific URL pattern
    var specificBlogs = context.Blogs
                               .Where(b => b.Url.Contains("microsoft.com"))
                               .ToList();
}
            

Adding Data

To add new entities, create instances of your entity classes and add them to the appropriate DbSet.

Example: Adding a New Blog


using (var context = new BloggingContext())
{
    var newBlog = new Blog { Url = "https://example.com/newsite" };
    context.Blogs.Add(newBlog); // Or context.Add(newBlog);
    context.SaveChanges(); // Persist changes to the database
}
            

Modifying Data

To update an entity, retrieve it from the context, modify its properties, and then call SaveChanges(). EF Core's change tracking handles the rest.

Example: Updating a Blog's URL


using (var context = new BloggingContext())
{
    var blogToUpdate = context.Blogs.FirstOrDefault(b => b.BlogId == 1);
    if (blogToUpdate != null)
    {
        blogToUpdate.Url = "https://example.com/updatedsite";
        context.SaveChanges(); // EF Core detects the change and generates an UPDATE statement
    }
}
            

Deleting Data

To delete an entity, retrieve it, and then remove it from the DbSet.

Example: Deleting a Blog


using (var context = new BloggingContext())
{
    var blogToDelete = context.Blogs.FirstOrDefault(b => b.BlogId == 2);
    if (blogToDelete != null)
    {
        context.Blogs.Remove(blogToDelete); // Or context.Remove(blogToDelete);
        context.SaveChanges(); // EF Core generates a DELETE statement
    }
}
            

Note on Change Tracking:

When you retrieve an entity using a DbContext instance, it becomes tracked by that context. Any modifications you make to tracked entities are automatically detected by EF Core when SaveChanges() is called. If you are working with entities that are not tracked (e.g., passed in from a different service), you may need to explicitly attach them to the context using context.Attach(entity) or set their state using context.Entry(entity).State = EntityState.Modified;.

Summary

DbContext and DbSet<TEntity> are fundamental to Entity Framework's data access capabilities. DbContext manages the session and change tracking, while DbSet<TEntity> represents collections of entities and enables LINQ querying and manipulation. Mastering these concepts is key to building robust and efficient data-driven applications with Entity Framework.