DEV Community

DotNet Full Stack Dev
DotNet Full Stack Dev

Posted on

Managing Multiple EF Core DbContexts in a Single Application

Entity Framework Core (EF Core) is a powerful ORM tool for working with databases in .NET applications. In some scenarios, you may need to work with multiple databases or database contexts within a single application. This could arise from the need to interact with different database schemas, manage separate databases for different modules, or integrate with external systems. In this blog post, we'll explore how to effectively manage multiple EF Core DbContexts in a single .NET application.

Define Multiple DbContext Classes

Start by defining separate DbContext classes for each database or database schema you need to work with.

Each DbContext class represents a distinct database context and should inherit from DbContext.

public class AppDbContext : DbContext
{
    // DbSet properties and configurations
}

public class AnotherDbContext : DbContext
{
    // DbSet properties and configurations
}
Enter fullscreen mode Exit fullscreen mode

Register DbContexts with Dependency Injection

In ASP.NET Core applications, register DbContext classes with the built-in dependency injection container.

Use the AddDbContext method to register each DbContext, specifying the connection string and options.

services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("AppConnection")));

services.AddDbContext<AnotherDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("AnotherConnection")));
Enter fullscreen mode Exit fullscreen mode

Accessing DbContext Instances

Inject the DbContext instances into your services or controllers where needed.

Use constructor injection to access the DbContext instances.

public class MyService
{
    private readonly AppDbContext _dbContext;

    public MyService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // Use _dbContext for database operations
}
Enter fullscreen mode Exit fullscreen mode

Managing Transactions Across DbContexts

When performing transactions involving multiple DbContexts, ensure proper coordination to maintain data integrity.

Use distributed transactions or implement a custom unit of work pattern if needed.

using (var transaction = _dbContext.Database.BeginTransaction())
{
    // Perform operations on _dbContext and AnotherDbContext
    transaction.Commit();
}
Enter fullscreen mode Exit fullscreen mode

Testing and Maintenance

Write integration tests to ensure that interactions between multiple DbContexts work as expected.

Regularly review and update DbContext configurations, including database connection strings and entity mappings.

Below is an example of an end-to-end order processing application using multiple EF Core DbContexts in a .NET application:

Define DbContext Classes

// AppDbContext.cs
public class AppDbContext : DbContext
{
    public DbSet<Order> Orders { get; set; }
    // Other DbSet properties and configurations
}

// CustomerDbContext.cs
public class CustomerDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    // Other DbSet properties and configurations
}
Enter fullscreen mode Exit fullscreen mode

Register DbContexts with Dependency Injection

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("AppConnection")));

    services.AddDbContext<CustomerDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("CustomerConnection")));

    services.AddScoped<IOrderService, OrderService>();
    services.AddScoped<ICustomerService, CustomerService>();
}
Enter fullscreen mode Exit fullscreen mode

Implement Order and Customer Services

// IOrderService.cs
public interface IOrderService
{
    Task<Order> GetOrderById(int id);
    Task CreateOrder(Order order);
    // Other order-related methods
}

// OrderService.cs
public class OrderService : IOrderService
{
    private readonly AppDbContext _dbContext;

    public OrderService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<Order> GetOrderById(int id)
    {
        return await _dbContext.Orders.FindAsync(id);
    }

    public async Task CreateOrder(Order order)
    {
        _dbContext.Orders.Add(order);
        await _dbContext.SaveChangesAsync();
    }
    // Implement other order-related methods
}

// ICustomerService.cs
public interface ICustomerService
{
    Task<Customer> GetCustomerById(int id);
    // Other customer-related methods
}

// CustomerService.cs
public class CustomerService : ICustomerService
{
    private readonly CustomerDbContext _dbContext;

    public CustomerService(CustomerDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<Customer> GetCustomerById(int id)
    {
        return await _dbContext.Customers.FindAsync(id);
    }
    // Implement other customer-related methods
}
Enter fullscreen mode Exit fullscreen mode

Usage in Controllers

// OrderController.cs
[ApiController]
[Route("[controller]")]
public class OrderController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrderController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetOrder(int id)
    {
        var order = await _orderService.GetOrderById(id);
        if (order == null)
            return NotFound();
        return Ok(order);
    }

    [HttpPost]
    public async Task<IActionResult> CreateOrder(Order order)
    {
        await _orderService.CreateOrder(order);
        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }
}
Enter fullscreen mode Exit fullscreen mode
// CustomerController.cs
[ApiController]
[Route("[controller]")]
public class CustomerController : ControllerBase
{
    private readonly ICustomerService _customerService;

    public CustomerController(ICustomerService customerService)
    {
        _customerService = customerService;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetCustomer(int id)
    {
        var customer = await _customerService.GetCustomerById(id);
        if (customer == null)
            return NotFound();
        return Ok(customer);
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Managing multiple EF Core DbContexts in a single application requires careful planning and implementation. By defining separate DbContext classes, registering them with dependency injection, and effectively coordinating transactions, you can work with multiple databases seamlessly within your .NET application. Additionally, thorough testing and maintenance practices ensure the reliability and performance of your application's database interactions.

Top comments (0)