How to Use Multiple DbContexts in Entity Framework Core (With Real-World Example)


How to Use Multiple DbContexts in Entity Framework Core


What Is DbContext?

    In Entity Framework Core, DbContext acts as a bridge between your application and the database. It handles querying, saving, and managing entities. But when your app scales or gets more complex, you may run into scenarios where using a single DbContext isn’t enough - and that’s where multi-DbContext design shines.

What Is Multi-DbContext?

    Multi-DbContext means creating and using more than one DbContext in your application. Instead of having a single context for the entire database, we split our data access into multiple smaller DbContext classes - each handling a specific module, feature, or part of the data.

    For example, I used separate contexts like AuthorDbContext and PostDbContext for different parts of my project. This way, each context is responsible only for what it needs.

    This approach is helpful when your app becomes large and you want better control over performance, responsibilities, or need to avoid thread-safety issues in asynchronous methods.

Why I Chose Multiple DbContexts in My Scenario

Problem: Concurrency Exceptions in Asynchronous Code

    Entity Framework Core’s DbContext is not thread-safe, which means you cannot perform multiple database operations in parallel using the same instance.

    In my initial implementation, I tried to fetch data for both Author and Post entities simultaneously using a single DbContext:

builder.Services.AddDbContext<SingleDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

    It worked fine… until I hit a real-world problem.

public async Task TriggerConcurrencyError()
{
    var taskOne = _singleDbContext.Author.FirstOrDefaultAsync();
    var taskTwo = _singleDbContext.Post.FirstOrDefaultAsync();

    await Task.WhenAll(taskOne, taskTwo);
}

    This looks fine at first, but it throws this error:

    A second operation was started on this context instance before a previous operation was completed.

Why?

    Because Entity Framework DbContext isn’t thread-safe. When two operations are triggered at the same time on the same context instance (like above), it fails.

What Did I Do?

    I split the logic into two separate contexts.

builder.Services.AddDbContext<AuthorDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddDbContext<PostDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

    Then my async call became:

public async Task FixedVersion()
{
    var taskOne = _authorDbContext.Author.FirstOrDefaultAsync();
    var taskTwo = _postDbContext.Post.FirstOrDefaultAsync();

    await Task.WhenAll(taskOne, taskTwo);
}

    This fixed the issue completely because now each async operation uses a separate DbContext. No sharing. No conflict.

You can access the complete source code on GitHub: Visit the Repository


Pros of Using Multi-DbContext

  • Avoids async concurrency issues: Prevents EF Core errors when two async operations happen on a single context.
  • Better separation of logic: Each context handles only what it needs, making the code cleaner and easier to test.
  • Scales well in big apps: Each module grows independently without breaking other modules.
  • Helps in team collaboration: Developers can work on different contexts without interfering with each other.
  • Reduces bugs during changes: Changes in one context don’t affect others due to isolation.

Cons of Using Multi-DbContext

  • More boilerplate code: You'll need to configure and register each context separately in the DI container.
  • Higher memory usage: Each context maintains its own resources, so using many at once consumes more memory.
  • Managing transactions is harder: Cross-context transactions require more setup or use of shared DbConnections.
  • Code navigation becomes scattered: It might be harder to follow logic across multiple contexts if not organized well.
  • More DI complexity: You must handle context lifetime and configuration correctly for each module.

Conclusion

    That’s how and why I ended up using multiple DbContexts in my app. It’s not the only solution, but in my case, it gave me better control, helped avoid concurrency issues, and kept my architecture clean.

Post a Comment

0 Comments