Search code examples
asp.net-core.net-coreaspnetboilerplate

How to use multiples databases in ABP Core Zero?


I want to isolate the "account" tables from "data" tables for reusing on another application.
I trying to use .NET Core 2.0 + Angular template, creating 2 connection strings, but when a create the another AbpDbContext, I couldn't set the connection strings for the context.
The example of using multiples DB contexts on their GitHub uses .NET framework, not .NET core, which is permitted to set the connection string on dbcontext ctor. How can I do this on .net core 2 template?


Solution

  • 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.