How to use multiples databases in ABP Core Zero?

Connect with multiple database in ASP.NET ZERO/ASP.NET BOILERPLATE.

Note - Use seperate DB Context to use multiple Databases.

Step 1. Create modal class in "MultipleDbContextEfCoreDemo.Core" Project for your tables.

[Table ("tblStudent")] //Is in First Database
public class Student : Entity<long> {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    protected Student () { }
}

[Table ("tblCourses")] //Is in Second Database
public class Courses : Entity<long> {
    public int ID { get; set; }
    public string CourseName { get; set; }
    public string Standard { get; set; }

    protected Courses () { }
}

Step 2. In same project("MultipleDbContextEfCoreDemo.Core" Project) create/use "MultipleDbContextEfCoreDemoConsts.cs" file to add Database Connection names.

public class MultipleDbContextEfCoreDemoConsts
    {
        public const string LocalizationSourceName = "MultipleDbContextEfCoreDemo";

        public const string ConnectionStringName = "Default";

        public const string SecondDbConnectionStringName = "Second";
    }

Step 3. In "MultipleDbContextEfCoreDemo.EntityFrameworkCore" Project goto "EntityFrameworkCore" Folder and create individual "DBContext" and "DbContextConfigurer" file for each database connection to which you want to connect.

FirstDatabase Setting -

required files to connect to first db -

1. FirstDbContext.cs

public class FirstDbContext : AbpDbContext, IAbpPersistedGrantDbContext {
    /* Define an IDbSet for each entity of the application */
    public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
    public virtual DbSet<Student> Student { get; set; }

    public FirstDbContext (DbContextOptions<FirstDbContext> options) : base (options) {

    }

    protected override void OnModelCreating (ModelBuilder modelBuilder) { }
}

2. FirstDbContextConfigurer

public static class FirstDbContextConfigurer {
    public static void Configure (DbContextOptionsBuilder<FirstDbContext> builder, string connectionString) {
        builder.UseSqlServer (connectionString);
    }

    public static void Configure (DbContextOptionsBuilder<FirstDbContext> builder, DbConnection connection) {
        builder.UseSqlServer (connection);
    }
}

SecondDatabase Setting -

required files to connect to second db -

1. SecondDbContext.cs

public class SecondDbContext : AbpDbContext, IAbpPersistedGrantDbContext {
    /* Define an IDbSet for each entity of the application */
    public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
    public virtual DbSet<Student> Student { get; set; }

    public SecondDbContext (DbContextOptions<SecondDbContext> options) : base (options) {

    }

    protected override void OnModelCreating (ModelBuilder modelBuilder) { }
}

2. SecondDbContextConfigurer

public static class SecondDbContextConfigurer {
    public static void Configure (DbContextOptionsBuilder<SecondDbContext> builder, string connectionString) {
        builder.UseSqlServer (connectionString);
    }
    public static void Configure (DbContextOptionsBuilder<SecondDbContext> builder, DbConnection connection) {
        builder.UseSqlServer (connection);
    }
}

Step 4. Then in same project("MultipleDbContextEfCoreDemo.EntityFrameworkCore") add "MyConnectionStringResolver.cs"

public class MyConnectionStringResolver : DefaultConnectionStringResolver
        {
            public MyConnectionStringResolver(IAbpStartupConfiguration configuration) 
                : base(configuration)
            {
            }

            public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
            {
                if (args["DbContextConcreteType"] as Type == typeof(SecondDbContext))
                {
                    var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
                    return configuration.GetConnectionString(MultipleDbContextEfCoreDemoConsts.SecondDbConnectionStringName);
                }

                return base.GetNameOrConnectionString(args);
            }
        }

Step 5. Then in same project("MultipleDbContextEfCoreDemo.EntityFrameworkCore"), Update "MultipleDbContextEfCoreDemoEntityFrameworkCoreModule.cs" file to replace the "IConnectionStringResolver" with our custom implementation MyConnectionStringResolver.

[DependsOn(typeof(MultipleDbContextEfCoreDemoCoreModule), typeof(AbpEntityFrameworkCoreModule))]
    public class MultipleDbContextEfCoreDemoEntityFrameworkCoreModule : AbpModule
    {
        public override void PreInitialize()
        {
            Configuration.ReplaceService<IConnectionStringResolver, MyConnectionStringResolver>();

            // Configure first DbContext
            Configuration.Modules.AbpEfCore().AddDbContext<FirstDbContext>(options =>
            {
                if (options.ExistingConnection != null)
                {
                    FirstDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
                }
                else
                {
                    FirstDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
                }
            });

            // Configure second DbContext
            Configuration.Modules.AbpEfCore().AddDbContext<SecondDbContext>(options =>
            {
                if (options.ExistingConnection != null)
                {
                    SecondDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
                }
                else
                {
                    SecondDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
                }
            });
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(MultipleDbContextEfCoreDemoEntityFrameworkCoreModule).GetAssembly());
        }
    }

Step 6. Create the Service in "MultipleDbContextEfCoreDemo.Application" project with Dto, Interface and Service Class.

ITestAppService.cs-

public interface ITestAppService : IApplicationService
    {
        List<string> GetStudentAndCourses();

     }

TestAppService.cs

public class TestAppService : MultipleDbContextEfCoreDemoAppServiceBase, ITestAppService
    {
        private readonly IRepository<Student> _studentRepository; //in the first db
        private readonly IRepository<Courses> _coursesRepository; //in the second db

        public TestAppService(
            IRepository<Student> studentRepository,
            IRepository<Courses> coursesRepository
        )
        {
            _studentRepository = studentRepository;
            _coursesRepository = coursesRepository;
        }

        //a sample method uses both databases concurrently
        public List<string> GetStudentAndCourses()
        {
            List<string> names = new List<string>();

            var studentNames = _studentRepository.GetAllList().Select(p => "Student: " + p.FirstName).ToList();
            names.AddRange(peopleNames);

            var courseNames = _coursesRepository.GetAllList().Select(p => "Course: " + p.CourseName).ToList();
            names.AddRange(courseNames);

            return names;
        }
    }

Step 7. Add Database connectionStrings to your MultipleDbContextEfCoreDemo.Web/MultipleDbContextEfCoreDemo.Web.Host project's "appsettings.json" file.

{
  "ConnectionStrings": {
    "Default":
      "Server=XXX.XXX.XX.XX;Database=firstDB;Integrated Security=False;TrustServerCertificate=True;User ID=XX;Password=XXX;",
    "Second":
      "Server=XXX.XXX.XX.XX;Database=secondDB;Integrated Security=False;TrustServerCertificate=True;User ID=XX;Password=XXX;"
  }
  }

Step 8. Use Service in your angular/MVC project.


I ran into the same problem as @Sniipe with regards to navigational properties.

The problem was that I was inheriting from

 AbpZeroDbContext<Tenant, Role, User, PortalDbContext>

in my second DBContext instead of just

AbpDbContext