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, whereT
is the type of the entity (for example,User
orProduct
).
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 fromDbContext
- Within this class, we defined two
DbSet
properties:Products
andCustomers
- 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.