Search code examples
c#entity-frameworkasp.net-coredomain-driven-designardalis-cleanarchitecture

How to dealing with multy source Database using DbContext


I used clean arch steps to create the project, but the problem that i have more then three aggregate that i need to put them in referents Database.

I tried to use DbContext for each aggregate like this:

public class AppDbContext : DbContext
{
  private readonly IMediator? _mediator;

  public AppDbContext(DbContextOptions<AppDbContext> options, IMediator? mediator)
      : base(options)
  {
    _mediator = mediator;
  }
.
.
.
public class AnalyzeDbContext : DbContext
{
  private readonly IMediator? _mediator;

  public AnalyzeDbContext(DbContextOptions<AnalyzeDbContext> options, IMediator? mediator)
      : base(options)
  {
    _mediator = mediator;
  }
.
.
.
public class ProviderMgrDbContext : DbContext
{
  private readonly IMediator? _mediator;


  public ProviderMgrDbContext(DbContextOptions<ProviderMgrDbContext> options, IMediator? mediator)
      : base(options)
  {
    _mediator = mediator;
  }

And i send the connection string for each DbContext like this:

//#Update 1
 public static void AppDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AppDbContext>(options => options.UseMySQL(connectionString));

 public static void ProviderMgrDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<ProviderMgrDbContext>(options => options.UseMySQL(connectionString));

  public static void AnalyzeDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AnalyzeDbContext>(options => options.UseMySQL(connectionString));

//#After
public static void AppDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AppDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));

 public static void ProviderMgrDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<ProviderMgrDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));
  
  public static void AnalyzeDbContext(this IServiceCollection services, string connectionString) =>
   services.AddDbContext<AnalyzeDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 27))));
.
.
.

But when i try to migrate them it's show exemption error like this:

PM> Add-Migration init_1 -context AppDbContext
Build started...
Build succeeded.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating WetaPayment.Infrastructure.Data.DataContext.AppDbContext.
 ---> Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor(Microsoft.EntityFrameworkCore.DbContextOptions`1[WetaPayment.Infrastructure.Data.DataContext.AppDbContext], MediatR.IMediator)' on type 'AppDbContext'.
 ---> System.TypeLoadException: Method 'AppendIdentityWhereCondition' in type 'MySql.EntityFrameworkCore.MySQLUpdateSqlGenerator' from assembly 'MySql.EntityFrameworkCore, Version=5.0.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' does not have an implementation.

Finally I fixed part of the problem with change MySql.EntityFrameworkCore package that was not compatible with net6.0 so i used Pomelo.EntityFrameworkCore.MySql and it's worked successfully.

But still i have another problem that is my all aggregate balded in all context, and i need each DbContext build only his aggregate, so how to fix it ?


Solution

  • Each DbContext can config their own entity

    Let assume we have 10 entities for 3 DbContext, we can separate them out 2 entities for ADbContext, 5 for BDbContext and 3 for CDbContext. Manage the configuration like FK, between them wisely, otherwise, that would turn to be chaos. Here is how to doing this, using fluent API

    public class MyAppDbContext : DbContext
    {
        public DbSet<OurEntity> OurEntity { get; set; }
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<OurEntity>(builder => 
           {
                // Our implementation goes here...
           });
        }
    }
    

    Like that, we config and register only entities correspondingly with each DbContext.

    We need to register each DbContext separately to whatever kind of DI

    Organize Migration operation for each DbContext

    I usually organize them in folder like this:

    Data/Migrations/ContextA
    Data/Migrations/ContextB
    Data/Migrations/ContextC
    

    Each context have their own Migrations and snapshot.

    Doing this by specify separate DbContext when using EF migration tool

    add-migration add [MigrationName] -context [DbContextName] -o [Path to desire place to store migration]
    

    then apply them separately by

    update-database -context [DbContextName]