Added suuport to inject an IOqtaneDatabase in EntityBuilders to allow each Database to control certain Migration behaviors. Also updated Installer to dynamically build Database Configuration section

This commit is contained in:
Charles Nurse
2021-03-27 11:16:16 -07:00
parent 3a032f401a
commit 2fb63e8117
74 changed files with 1028 additions and 407 deletions

View File

@ -1,10 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Oqtane.Extensions;
using Oqtane.Interfaces;
using Oqtane.Migrations.Framework;
using Oqtane.Repository.Databases.Interfaces;
using Oqtane.Shared;
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
@ -32,11 +38,16 @@ namespace Oqtane.Repository
_configuration = dbConfig.Configuration;
_connectionString = dbConfig.ConnectionString;
_databaseType = dbConfig.DatabaseType;
Databases = dbConfig.Databases;
_tenantResolver = tenantResolver;
}
public IEnumerable<IOqtaneDatabase> Databases { get; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
if (string.IsNullOrEmpty(_connectionString) && _tenantResolver != null)
{
var tenant = _tenantResolver.GetTenant();
@ -60,7 +71,14 @@ namespace Oqtane.Repository
if (!string.IsNullOrEmpty(_connectionString) && !string.IsNullOrEmpty(_databaseType))
{
optionsBuilder.UseOqtaneDatabase(_databaseType, _connectionString);
if (Databases != null)
{
optionsBuilder.UseOqtaneDatabase(Databases.Single(d => d.Name == _databaseType), _connectionString);
}
else
{
optionsBuilder.UseOqtaneDatabase(_databaseType, _connectionString);
}
}
base.OnConfiguring(optionsBuilder);

View File

@ -1,20 +1,25 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Oqtane.Interfaces;
namespace Oqtane.Repository
{
public class DbConfig : IDbConfig
{
public DbConfig(IHttpContextAccessor accessor, IConfiguration configuration)
public DbConfig(IHttpContextAccessor accessor, IConfiguration configuration, IEnumerable<IOqtaneDatabase> databases)
{
Accessor = accessor;
Configuration = configuration;
Databases = databases;
}
public IHttpContextAccessor Accessor { get; }
public IConfiguration Configuration { get; }
public IEnumerable<IOqtaneDatabase> Databases { get; set; }
public string ConnectionString { get; set; }
public string DatabaseType { get; set; }

View File

@ -1,24 +1,29 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Oqtane.Extensions;
using Oqtane.Interfaces;
using Oqtane.Models;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Oqtane.Repository
{
public class InstallationContext : DbContext
{
private readonly string _connectionString;
private readonly string _databaseType;
private readonly IOqtaneDatabase _database;
public InstallationContext(string databaseType, string connectionString)
public InstallationContext(IOqtaneDatabase database, string connectionString)
{
_connectionString = connectionString;
_databaseType = databaseType;
_database = database;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseOqtaneDatabase(_databaseType, _connectionString);
=> optionsBuilder.UseOqtaneDatabase(_database, _connectionString);
public virtual DbSet<Alias> Alias { get; set; }
public virtual DbSet<Tenant> Tenant { get; set; }

View File

@ -1,9 +1,14 @@
using System;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Oqtane.Models;
using Microsoft.Extensions.Configuration;
using Oqtane.Extensions;
using Oqtane.Interfaces;
using Oqtane.Migrations.Framework;
using Oqtane.Repository.Databases.Interfaces;
using Oqtane.Shared;
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
@ -12,17 +17,22 @@ using Oqtane.Shared;
namespace Oqtane.Repository
{
public class MasterDBContext : DbContext
public class MasterDBContext : DbContext, IMultiDatabase
{
private readonly IDbConfig _dbConfig;
public MasterDBContext(DbContextOptions<MasterDBContext> options, IDbConfig dbConfig) : base(options)
{
_dbConfig = dbConfig;
Databases = dbConfig.Databases;
}
public IEnumerable<IOqtaneDatabase> Databases { get; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
var connectionString = _dbConfig.ConnectionString;
var configuration = _dbConfig.Configuration;
var databaseType = _dbConfig.DatabaseType;
@ -38,10 +48,18 @@ namespace Oqtane.Repository
databaseType = configuration.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
}
if (!string.IsNullOrEmpty(connectionString))
if (!string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(databaseType))
{
optionsBuilder.UseOqtaneDatabase(databaseType, connectionString);
if (Databases != null)
{
optionsBuilder.UseOqtaneDatabase(Databases.Single(d => d.Name == databaseType), connectionString);
}
else
{
optionsBuilder.UseOqtaneDatabase(databaseType, connectionString);
}
}
base.OnConfiguring(optionsBuilder);
}

View File

@ -1,12 +1,19 @@
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Oqtane.Interfaces;
using Oqtane.Models;
using Oqtane.Repository.Databases.Interfaces;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Oqtane.Repository
{
public class TenantDBContext : DBContextBase
public class TenantDBContext : DBContextBase, IMultiDatabase
{
public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) { }
public virtual DbSet<Site> Site { get; set; }
public virtual DbSet<Page> Page { get; set; }
public virtual DbSet<PageModule> PageModule { get; set; }
@ -21,13 +28,6 @@ namespace Oqtane.Repository
public virtual DbSet<Notification> Notification { get; set; }
public virtual DbSet<Folder> Folder { get; set; }
public virtual DbSet<File> File { get; set; }
public virtual DbSet<Language> Language { get; set; }
public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver)
{
// DBContextBase handles multi-tenant database connections
}
}
}

View File

@ -1,5 +1,7 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Oqtane.Interfaces;
namespace Oqtane.Repository
{
@ -9,7 +11,10 @@ namespace Oqtane.Repository
public IConfiguration Configuration { get; }
public IEnumerable<IOqtaneDatabase> Databases { get; set; }
public string ConnectionString { get; set; }
public string DatabaseType { get; set; }
}
}