# Using Multiple EF Core DbContexts In a Single Application

> It's common to have only one DbContext for the entire application. But what if you need multiple DbContexts? We're going to explore when you may want them, how to create them, and what the benefits are.

Published: 2023-03-11. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/using-multiple-ef-core-dbcontext-in-single-application

You can register more than one `DbContext` in a single application by calling `AddDbContext` once per context.
Use it when the app spans multiple databases, when you want a read-replica context, or to give each module of a modular monolith its own schema with `HasDefaultSchema`.
Joins and shared transactions across contexts are limited.

**Entity Framework Core (EF Core)** is a popular ORM in .NET that allows you to work with SQL databases.
EF Core uses a `DbContext`, which represents a session with the database and is responsible for tracking changes,
performing database operations, and managing database connections.

It's common to have only one `DbContext` for the entire application.

But what if you need to have **multiple DbContexts**?

In this week's newsletter we're going to explore:

- When you may want to use multiple DbContexts
- How to create multiple DbContexts
- What are the benefits of using multiple DbContexts

Let's dive in!

## Why Use Multiple DbContexts?

There are a few cases where using **multiple DbContexts can be useful.**

**Multiple Databases**\
Does your application need to work with multiple SQL databases?
Then you're forced to use multiple DbContexts, each one dedicated to a specific SQL database.

**Separating Concerns**\
If the application you're building has a complex domain model, you may see an improvement by separating concerns
between a few DbContexts, where each one is responsible for a specific area of the domain model.

**Modular Monolith**\
When you're building a [**Modular Monolith**](https://milanjovanovic.tech/blog/modular-monolith-architecture-dotnet), using multiple DbContexts can be practical because you can configure
a different **database schema** per `DbContext`, giving you logical separation at the database level.

**Read Replicas**\
You can configure a separate `DbContext` instance to access the read replica of your database, and use that
`DbContext` for read-only queries.
You can also configure `QueryTrackingBehavior.NoTracking` on the `DbContext` level to [**improve query performance**](https://milanjovanovic.tech/blog/ef-core-performance-guide).

## Creating Multiple DbContexts In a Single Application

Here's how you can easily configure multiple DbContexts.
Let's say we have a `CatalogDbContext` and an `OrderDbContext` in our application.
We want to configure them using the following constrainsts:

- Both DbContexts use the **same database**
- Each DbContext has a **separate database schema**

```csharp
public class CatalogDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    public DbSet<Category> Categories { get; set; }
}

public class OrderDbContext : DbContext
{
    public DbSet<Order> Orders { get; set; }

    public DbSet<LineItem> LineItems { get; set; }
}
```

First we need to configure the `CatalogDbContext` and `OrderDbContext` with the DI container.
You can do this by calling the `AddDbContext` method and specifying which `DbContext` is being configured,
and then using the SQL provider specific method to pass the connection string.
In this case I'm connecting to SQL Server with the `UseSqlServer` method.

```csharp
using Microsoft.EntityFrameworkCore;

services.AddDbContext<CatalogDbContext>(options =>
    options.UseSqlServer("CONNECTION_STRING"));

services.AddDbContext<OrderDbContext>(options =>
    options.UseSqlServer("CONNECTION_STRING"));
```

If you just want to use both DbContexts in the same schema, then this is all the configuration you need.
You can now inject the `DbContext` instances in your application and use them.

However, if you want to configure a different schema for each `DbContext` then you also need to override
the `OnModelCreating` method and specify the custom schema with `HasDefaultSchema`.

```csharp
public class CatalogDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    public DbSet<Category> Categories { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("catalog");
    }
}

public class OrderDbContext : DbContext
{
    public DbSet<Order> Orders { get; set; }

    public DbSet<LineItem> LineItems { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("order");
    }
}
```

Limitations with multiple DbContexts:

1. It's not possible to do a join between different `DbContext` instances, because **EF Core** doesn't know if they
   are using the same database
2. Transactions will only work if the DbContexts are using the same database. You have to create a new transaction
   and share it between the DbContexts by [calling the `UseTransaction` method](https://milanjovanovic.tech/blog/working-with-transactions-in-ef-core#using-existing-transactions-with-ef-core)

**Migrations History Table**

If you decide to use different schemas per `DbContext`, you will be unpleasantly surprised to learn
that the default schema doesn't apply to the migrations history table.

You need to configure this by calling the `MigrationsHistoryTable` method and specifying the table name
and schema where the migrations history for that context will live.
I used the `HistoryRepository.DefaultTableName` constant in this example, but you can specify a custom
table name if you want to.

```csharp
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;

services.AddDbContext<CatalogDbContext>(options =>
    options.UseSqlServer(
        "CONNECTION_STRING",
        o => o.MigrationsHistoryTable(
            tableName: HistoryRepository.DefaultTableName,
            schema: "catalog")));

services.AddDbContext<OrderDbContext>(options =>
    options.UseSqlServer(
        "CONNECTION_STRING",
        o => o.MigrationsHistoryTable(
            tableName: HistoryRepository.DefaultTableName,
            schema: "order")));
```

## Benefits Of Using Multiple DbContexts

Using multiple DbContexts can offer several benefits to your application:

- Separation of concerns
- Better performance
- More control & security

Each DbContext can be responsible for a specific subset of the application's data, which can help organize the code
and make it more modular.

When you separate data access into multiple DbContexts, the application can reduce the risk of contention and improve
concurrency, and this can improve performance.

And if you're using multiple DbContexts, you can configure more granular access control to improve application security.
You can also optimize performance and resource usage.

## In Summary

Using **multiple EF Core DbContexts** in a single application is straightforward and has many benefits.

For ready-heavy applications you can configure a separate `DbContext` to turn off query tracking by default
and get improved performance.

Also, using multiple DbContexts is practical if you're building a **Modular monolith**.
You can configure the DbContexts to be in **separate database schemas**, giving you logical separation at the database level.

That's all for today.

See you next week.

---

## Frequently asked questions

### When should you use multiple DbContexts in one application?

Use multiple DbContexts when the application works with multiple databases, when you want to separate concerns in a complex domain model, when you are building a modular monolith, or when you want a dedicated context for querying a read replica.

### How do you configure a separate database schema per DbContext?

Override OnModelCreating in each DbContext and call HasDefaultSchema with the schema name. Also configure the migrations history table per context with the MigrationsHistoryTable method, because the default schema does not apply to the migrations history table.

### Can you join entities from two different DbContexts?

No. It is not possible to do a join between different DbContext instances, because EF Core does not know whether the two contexts are using the same database.

### Do transactions work across multiple DbContexts?

Only when the DbContexts use the same database. You have to create a new transaction yourself and share it between the DbContexts by calling the UseTransaction method.

### Why use multiple DbContexts in a modular monolith?

Each module can get its own DbContext configured with a different database schema, giving you logical separation at the database level while everything still lives in a single database.

### How can a separate DbContext improve read performance?

You can configure a separate DbContext to access the read replica of your database and use it for read-only queries. Configuring QueryTrackingBehavior.NoTracking at the DbContext level improves query performance for those reads.
