entity-framework-configuracion-dbcontext

What is DbContext and how to use it in Entity Framework

  • 4 min

In this tutorial, we will explore the DBContext, object that represents the central component of Entity Framework and acts as a bridge between our .NET application and the underlying database.

The DBContext is the main class that allows us to interact with the database without writing SQL directly, providing the methods to perform read, write, update, and delete operations on data.

Key features

  • Allows defining the data model using DbSet<T> properties
  • Manages connections with the database
  • Allows querying the database using LINQ
  • Offers methods to manage the lifecycle of entities

In other words, it is the most important class and the core of Entity Framework, as it allows us to interact with the database without the need to write SQL manually.

Basic DbContext Configuration

To use the DbContext class, we typically create a class that inherits from it, in which we define which tables (entities) will be associated with our database.

Inside our DbContext class (which inherits from it)

  • We will define properties of type DbSet<T>, which represent the tables in the database.
  • Each DbSet<T> allows interaction with the associated table, where T is the type of the entity (for example, User or Product).

Let’s see it with an example,

using Microsoft.EntityFrameworkCore;

public class MyContext : DbContext
{
    // Represents the "Products" table in the database
    public DbSet<Product> Products { get; set; }

    // Represents the "Customers" table in the database
    public DbSet<Customer> Customers { get; set; }
}

In this example,

  • We created a class named MyContext that inherits from DbContext
  • Within this class, we defined two DbSet properties: Products and Customers
  • These properties represent the tables in the database.

Configuring the Database Connection

The DbContext needs to know how to connect to the database. We have several ways to pass it the configuration,

In applications where we do not have a dependency injection service (typically console or desktop applications), we can use the OnConfiguring method to set the configuration

public class MyContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Customer> Customers { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
	    const string connectionString = Configuration.GetConnectionString("DefaultConnection");

        // Configures the connection to SQL Server
        optionsBuilder.UseSqlServer(connectionString);
    }
}

In this example, we have overridden the OnConfiguring method to specify the connection string to SQL Server.

In ASP.NET Core applications, it is common and recommended to use dependency injection to configure the DbContext.

Generally, this will be configured in the Program.cs file of the application, using the AddDbContext method of the service container,

const string connectionString = Configuration.GetConnectionString("DefaultConnection");

// Configures the DbContext to use SQL Server
services.AddDbContext<MyContext>(options =>
    options.UseSqlServer(connectionString)
);

In some applications, the scope of dependency injection does not match the desired lifetime of the DbContext (for example, in Blazor, where the connection is persistent, not per request).

In this case, we can register a factory that can create new instances of DbContext on demand,

services.AddDbContextFactory<MyContext>(options => 
    options.UseSqlServer(connectionString);

Afterward, services that use the factory could create a new DbContext by doing

MyContext context = _contextFactory.CreateDbContext()

Proper Lifecycle Usage

The DbContext should have a limited lifecycle. It is generally configured as Scoped in the DI container, which ensures that an instance is created for each HTTP request.

Common Operations with the DbContext

Now that we have configured our DbContext and defined the classes with DbSet, we can perform operations with it.

For example, let’s see some of the basic CRUD operations (Create, Read, Update, and Delete)

The Add or AddRange method is used to insert new entities into the database:

var newUser = new User { Name = "Luis Llamas", Email = "[email protected]" };
_context.Users.Add(newUser);
await _context.SaveChangesAsync();

Queries are performed using LINQ:

var user = await _context.Users
    .FirstOrDefaultAsync(u => u.Email == "[email protected]");

Modify the data in memory and save the changes:

var user = await _context.Users.FindAsync(1);
if (user != null)
{
    user.Name = "Luis Updated";
    await _context.SaveChangesAsync();
}

Delete entities using Remove:

var user = await _context.Users.FindAsync(1);
if (user != null)
{
    _context.Users.Remove(user);
    await _context.SaveChangesAsync();
}

Isn’t it easy? But there’s much more! We will explore all these elements in depth in the upcoming tutorials.