417.3 Multi‐Tenancy of ABP framework applications - chempkovsky/CS82ANGULAR GitHub Wiki

Note
Entity
  • In the Second-folder of the rupbes.firstapp.Domain.csproj-project we created new Entity without TenantId-property, i.e. our Entity does not implement IMultiTenant-interface.
Click to show the code
using System;
using Volo.Abp.Domain.Entities;

namespace rupbes.firstapp.Second
{
    public class SecondEntity : Entity<Guid>
    {
        public virtual Guid Id { get; protected set; }
        public virtual int Intfld { get; protected set; }

        protected SecondEntity()
        {

        }
        public SecondEntity(Guid id, int intfld)
        {
            Id = id;
            SetIntfld(intfld);
        }
        public void SetIntfld(int value)
        {
            Intfld = value;
        }
    }
}
New DBContext
  • In the EntityFrameworkCore-folder of the rupbes.firstapp.EntityFrameworkCore.csproj-project we created new DB-context
Click to show the code
using Microsoft.EntityFrameworkCore;
using rupbes.firstapp.Phbk;
using rupbes.firstapp.Second;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;


// https://abp.io/docs/latest/framework/data/entity-framework-core/migrations
// dotnet ef migrations add Initial --context secondDbContext --output-dir SecondMigrations
// dotnet ef database update --context secondDbContext

namespace rupbes.firstapp.EntityFrameworkCore
{
    [ConnectionStringName("SecondConnStr")]
    public class secondDbContext : AbpDbContext<secondDbContext>
    {
        public secondDbContext(DbContextOptions<secondDbContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<SecondEntity>(b =>
            {
                b.ToTable(firstappConsts.DbTablePrefix + "SecondEntitys", firstappConsts.DbSchema);
                b.ConfigureByConvention(); //auto configure for the base class props
                //...
                b.HasKey(p => p.Id);
            });
            builder.Entity<PhbkFile>(b =>
            {
                b.ToTable(firstappConsts.DbTablePrefix + "PhbkFiles", firstappConsts.DbSchema);
                b.ConfigureByConvention(); //auto configure for the base class props
                //...
                b.HasKey(p => new { p.FileId, p.FlNm });
            });
        }

        public DbSet<PhbkFile> PhbkFileDbSet
        {
            get => Set<PhbkFile>();

        }


        public DbSet<SecondEntity> SecondEntityDbSet
        {
            get => Set<SecondEntity>();

        }
    }
}
New DBContext factory
  • In the EntityFrameworkCore-folder of the rupbes.firstapp.EntityFrameworkCore.csproj-project we created new DB-context factory
Click to show the code
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace rupbes.firstapp.EntityFrameworkCore
{
    internal class secondDbContextFactory : IDesignTimeDbContextFactory<secondDbContext>
    {
        public secondDbContext CreateDbContext(string[] args)
        {
            var configuration = BuildConfiguration();

            firstappEfCoreEntityExtensionMappings.Configure();

            var builder = new DbContextOptionsBuilder<secondDbContext>()
                .UseSqlServer(configuration.GetConnectionString("SecondConnStr"));

            return new secondDbContext(builder.Options);
        }
        private static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../rupbes.firstapp.DbMigrator/"))
                .AddJsonFile("appsettings.json", optional: false);

            return builder.Build();
        }

    }
}
appsettings
  • we modified appsettings.json-file of the rupbes.firstapp.DbMigrator.csproj and rupbes.firstapp.HttpApi.Host.csproj projects
Click to show the code
{
  "ConnectionStrings": {
    "Default":       "Server=(LocalDb)\\MSSQLLocalDB;Database=firstapp;Trusted_Connection=True;TrustServerCertificate=true",
    "SecondConnStr": "Server=(LocalDb)\\MSSQLLocalDB;Database=sdc;Trusted_Connection=True;TrustServerCertificate=true"
  },
 ...
}
Register
  • We modified ConfigureServices(ServiceConfigurationContext context)-method of the firstappEntityFrameworkCoreModule-class:
Click to show the code
public override void ConfigureServices(ServiceConfigurationContext context)
{
    context.Services.AddAbpDbContext<firstappDbContext>(options =>
    {
            /* Remove "includeAllEntities: true" to create
             * default repositories only for aggregate roots */
        options.AddDefaultRepositories(includeAllEntities: true);
    });

    context.Services.AddAbpDbContext<secondDbContext>();

    if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
    {
        return;
    }

    Configure<AbpDbContextOptions>(options =>
    {
        /* The main point to change your DBMS.
         * See also firstappDbContextFactory for EF Core tooling. */

        options.UseSqlServer();

    });
    
}
Migrator
  • We modified MigrateAsync()-method of the EntityFrameworkCorefirstappDbSchemaMigrator-class of the rupbes.firstapp.EntityFrameworkCore.csproj-project
Click to show the code
    public async Task MigrateAsync()
    {
        /* We intentionally resolving the firstappDbContext
         * from IServiceProvider (instead of directly injecting it)
         * to properly get the connection string of the current tenant in the
         * current scope.
         */

        await _serviceProvider
            .GetRequiredService<firstappDbContext>()
            .Database
            .MigrateAsync();
        await _serviceProvider
            .GetRequiredService<secondDbContext>()
            .Database
            .MigrateAsync();

    }
ef migrations
  • In thw windows terminal we run the command
Click to show the code
D:\Development\rupbes.firstapp\src\rupbes.firstapp.EntityFrameworkCore>dotnet ef migrations add Initial --context secondDbContext --output-dir SecondMigrations
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
DbMigrator
  • we run rupbes.firstapp.DbMigrator.csproj-console app to create Host-database. It works. (New database was created)
Add row to TenantConnectionString
  • Using generated UI we added new row for the Tenant
Click to show the picture

project structure

DbMigrator again
  • we run rupbes.firstapp.DbMigrator.csproj-console app to create Tenant-database. It works. (New database was created)
⚠️ **GitHub.com Fallback** ⚠️