diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index ff57e0bf..7418a201 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -87,7 +87,7 @@ namespace Oqtane.Client } // dynamically register database providers - var databaseTypes = assembly.GetInterfaces(); + var databaseTypes = assembly.GetInterfaces(); foreach (var databaseType in databaseTypes) { if (databaseType.AssemblyQualifiedName != null) diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index 8f140012..3c013711 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -1,4 +1,5 @@ @using Oqtane.Interfaces +@using System.Reflection @namespace Oqtane.UI @inject NavigationManager NavigationManager @inject IInstallationService InstallationService @@ -6,7 +7,7 @@ @inject IUserService UserService @inject IJSRuntime JSRuntime @inject IStringLocalizer Localizer -@inject IEnumerable Databases +@inject IEnumerable Databases
@@ -36,57 +37,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @{ + _selectedDatabase = Databases.Single(d => d.Name == _databaseType); + foreach (var field in _selectedDatabase.ConnectionStringFields) + { + if (field.Name != "IntegratedSecurity") + { + var isVisible = ""; + var fieldType = (field.Name == "Pwd") ? "password" : "text"; + if ((field.Name == "Uid" || field.Name == "Pwd") && _selectedDatabase.Name != "MySQL" ) + { + var intSecurityField = _selectedDatabase.ConnectionStringFields.Single(f => f.Name == "IntegratedSecurity"); + if (intSecurityField != null) + { + isVisible = (Convert.ToBoolean(intSecurityField.Value)) ? "display: none;" : ""; + } + } + + field.Value = field.Value.Replace("{{Date}}", DateTime.UtcNow.ToString("yyyyMMddHHmm")); + + + + + + + + + + } + else + { + + + + + + + + + } + } + }
@@ -141,18 +135,13 @@
@code { + private IOqtaneDatabase _selectedDatabase; private string _databaseType = "LocalDB"; - private string _serverName = "(LocalDb)\\MSSQLLocalDB"; - private string _fileName = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm") + ".db"; - private string _databaseName = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm"); - private string _username = string.Empty; - private string _password = string.Empty; private string _hostUsername = UserNames.Host; private string _hostPassword = string.Empty; private string _confirmPassword = string.Empty; private string _hostEmail = string.Empty; private string _message = string.Empty; - private string _integratedSecurityDisplay = "display: none;"; private string _loadingDisplay = "display: none;"; protected override async Task OnAfterRenderAsync(bool firstRender) @@ -164,52 +153,21 @@ } } - private void SetIntegratedSecurity(ChangeEventArgs e) - { - _integratedSecurityDisplay = Convert.ToBoolean((string)e.Value) - ? "display: none;" - : string.Empty; - } - private async Task Install() { - if (((_serverName != "" && _databaseName != "") || _fileName !="") && _hostUsername != "" && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && _hostEmail != "") + var connectionString = _selectedDatabase.BuildConnectionString(); + + if (connectionString != "" && _hostUsername != "" && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && _hostEmail != "") { _loadingDisplay = ""; StateHasChanged(); - var connectionstring = ""; - var fullyQualifiedType = ""; - switch (_databaseType) - { - case "LocalDB": - connectionstring = "Data Source=" + _serverName + ";AttachDbFilename=|DataDirectory|\\" + _databaseName + ".mdf;Initial Catalog=" + _databaseName + ";Integrated Security=SSPI;"; - fullyQualifiedType = "Oqtane.Repository.Databases.LocalDbDatabase, Oqtane.Server"; - break; - case "SQLServer": - connectionstring = "Data Source=" + _serverName + ";Initial Catalog=" + _databaseName + ";"; - if (_integratedSecurityDisplay == "display: none;") - { - connectionstring += "Integrated Security=SSPI;"; - } - else - { - connectionstring += "User ID=" + _username + ";Password=" + _password; - } - fullyQualifiedType = "Oqtane.Repository.Databases.SqlServerDatabase, Oqtane.Server"; - break; - case "Sqlite": - connectionstring = "Data Source=" + _fileName; - fullyQualifiedType = "Oqtane.Repository.Databases.SqliteDatabase, Oqtane.Server"; - break; - } - Uri uri = new Uri(NavigationManager.Uri); var config = new InstallConfig { - DatabaseType = fullyQualifiedType, - ConnectionString = connectionstring, + DatabaseType = _databaseType, + ConnectionString = connectionString, Aliases = uri.Authority, HostEmail = _hostEmail, HostPassword = _hostPassword, @@ -218,8 +176,6 @@ IsNewTenant = true, SiteName = Constants.DefaultSite }; - - var installation = await InstallationService.Install(config); if (installation.Success) diff --git a/Oqtane.Database.MySQL/MySQLDatabase.cs b/Oqtane.Database.MySQL/MySQLDatabase.cs new file mode 100644 index 00000000..5691e8c6 --- /dev/null +++ b/Oqtane.Database.MySQL/MySQLDatabase.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using MySql.EntityFrameworkCore.Metadata; +using Oqtane.Interfaces; +using Oqtane.Models; + +namespace Oqtane.Database.MySQL +{ + public class MySQLDatabase : IOqtaneDatabase + { + public MySQLDatabase() + { + ConnectionStringFields = new List() + { + new() {Name = "Server", FriendlyName = "Server", Value = "127.0.0.1"}, + new() {Name = "Port", FriendlyName = "Port", Value = "3306"}, + new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}"}, + new() {Name = "Uid", FriendlyName = "User Id", Value = ""}, + new() {Name = "Pwd", FriendlyName = "Password", Value = ""} + }; + } + + public string FriendlyName => Name; + + public string Name => "MySQL"; + + public string Provider => "MySql.EntityFrameworkCore"; + + public List ConnectionStringFields { get; } + + public OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) + { + return table.Column(name: name, nullable: false).Annotation("MySQL:ValueGenerationStrategy", MySQLValueGenerationStrategy.IdentityColumn); + } + + public string BuildConnectionString() + { + var connectionString = String.Empty; + + var server = ConnectionStringFields[0].Value; + var port = ConnectionStringFields[1].Value; + var database = ConnectionStringFields[2].Value; + var userId = ConnectionStringFields[3].Value; + var password = ConnectionStringFields[4].Value; + + if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database) && !String.IsNullOrEmpty(userId) && !String.IsNullOrEmpty(password)) + { + connectionString = $"Server={server};Database={database};Uid={userId};Pwd={password};"; + } + + if (!String.IsNullOrEmpty(port)) + { + connectionString += $"Port={port};"; + } + return connectionString; + } + + public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + return optionsBuilder.UseMySQL(connectionString); + } + } +} diff --git a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj new file mode 100644 index 00000000..cc1cd306 --- /dev/null +++ b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj @@ -0,0 +1,16 @@ + + + + net5.0 + 9 + + + + + + + + + + + diff --git a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj new file mode 100644 index 00000000..6f1c3507 --- /dev/null +++ b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj @@ -0,0 +1,18 @@ + + + + 9 + net5.0 + + + + + + + + + + + + + diff --git a/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs new file mode 100644 index 00000000..9ba6ab63 --- /dev/null +++ b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; +using Oqtane.Models; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Oqtane.Database.PostgreSQL +{ + public class PostgreSQLDatabase : IOqtaneDatabase + { + + public PostgreSQLDatabase() + { + ConnectionStringFields = new List() + { + new() {Name = "Server", FriendlyName = "Server", Value = "127.0.0.1"}, + new() {Name = "Port", FriendlyName = "Port", Value = "5432"}, + new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}"}, + new() {Name = "IntegratedSecurity", FriendlyName = "Integrated Security", Value = "true"}, + new() {Name = "Uid", FriendlyName = "User Id", Value = ""}, + new() {Name = "Pwd", FriendlyName = "Password", Value = ""} + }; + } + + public string FriendlyName => Name; + + public string Name => "PostgreSQL"; + + public string Provider => "Npgsql.EntityFrameworkCore.PostgreSQL"; + + public List ConnectionStringFields { get; } + + public OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) + { + return table.Column(name: name, nullable: false).Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + } + + public string BuildConnectionString() + { + var connectionString = String.Empty; + + var server = ConnectionStringFields[0].Value; + var port = ConnectionStringFields[1].Value; + var database = ConnectionStringFields[2].Value; + var integratedSecurity = Boolean.Parse(ConnectionStringFields[3].Value); + var userId = ConnectionStringFields[4].Value; + var password = ConnectionStringFields[5].Value; + + if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database) && !String.IsNullOrEmpty(port)) + { + connectionString = $"Server={server};Port={port};Database={database};"; + } + + if (integratedSecurity) + { + connectionString += "Integrated Security=true;"; + } + else + { + if (!String.IsNullOrEmpty(userId) && !String.IsNullOrEmpty(password)) + { + connectionString += $"User ID={userId};Password={password};"; + } + else + { + connectionString = String.Empty; + } + } + + return connectionString; + } + + public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + return optionsBuilder.UseNpgsql(connectionString).UseSnakeCaseNamingConvention(); + } + } +} diff --git a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj new file mode 100644 index 00000000..75f13dad --- /dev/null +++ b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj @@ -0,0 +1,15 @@ + + + + net5.0 + + + + + + + + + + + diff --git a/Oqtane.Database.Sqlite/SqliteDatabase.cs b/Oqtane.Database.Sqlite/SqliteDatabase.cs new file mode 100644 index 00000000..62873409 --- /dev/null +++ b/Oqtane.Database.Sqlite/SqliteDatabase.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; +using Oqtane.Models; + +namespace Oqtane.Repository.Databases +{ + public class SqliteDatabase : IOqtaneDatabase + { + public SqliteDatabase() + { + ConnectionStringFields = new List() + { + new() {Name = "Server", FriendlyName = "File Name", Value = "Oqtane-{{Date}}.db"} + }; + } + + public string FriendlyName => Name; + + public string Name => "Sqlite"; + + public string Provider => "Microsoft.EntityFrameworkCore.Sqlite"; + + public List ConnectionStringFields { get; } + + public OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) + { + return table.Column(name: name, nullable: false).Annotation("Sqlite:Autoincrement", true); + } + + public string BuildConnectionString() + { + var connectionstring = String.Empty; + + var server = ConnectionStringFields[0].Value; + + if (!String.IsNullOrEmpty(server)) + { + connectionstring = $"Data Source={server};"; + } + + return connectionstring; + } + + public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + return optionsBuilder.UseSqlite(connectionString); + } + } +} diff --git a/Oqtane.Server/Databases/Interfaces/IMultiDatabase.cs b/Oqtane.Server/Databases/Interfaces/IMultiDatabase.cs new file mode 100644 index 00000000..103cd76b --- /dev/null +++ b/Oqtane.Server/Databases/Interfaces/IMultiDatabase.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Oqtane.Interfaces; + +namespace Oqtane.Repository.Databases.Interfaces +{ + public interface IMultiDatabase + { + public IEnumerable Databases { get; } + } +} diff --git a/Oqtane.Server/Databases/LocalDbDatabase.cs b/Oqtane.Server/Databases/LocalDbDatabase.cs index 0100c208..a0e0580d 100644 --- a/Oqtane.Server/Databases/LocalDbDatabase.cs +++ b/Oqtane.Server/Databases/LocalDbDatabase.cs @@ -1,16 +1,36 @@ -using Microsoft.EntityFrameworkCore; -using Oqtane.Interfaces; +using System; +using System.Collections.Generic; +using Oqtane.Models; +using Oqtane.Repository.Databases; -namespace Oqtane.Repository.Databases +namespace Oqtane.Databases { - public class LocalDbDatabase : IDatabase + public class LocalDbDatabase : SqlServerDatabaseBase { - public string FriendlyName => "Local Database"; - public string Name => "LocalDB"; + private static string _friendlyName => "Local Database"; + private static string _name => "LocalDB"; - public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + private static readonly List _connectionStringFields = new() { - return optionsBuilder.UseSqlServer(connectionString); + new() {Name = "Server", FriendlyName = "Server", Value = "(LocalDb)\\MSSQLLocalDB"}, + new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}"} + }; + + public LocalDbDatabase() :base(_name, _friendlyName, _connectionStringFields) { } + + public override string BuildConnectionString() + { + var connectionString = String.Empty; + + var server = ConnectionStringFields[0].Value; + var database = ConnectionStringFields[1].Value; + + if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database)) + { + connectionString = $"Data Source={server};AttachDbFilename=|DataDirectory|\\{database}.mdf;Initial Catalog={database};Integrated Security=SSPI;"; + } + + return connectionString; } } } diff --git a/Oqtane.Server/Databases/SqlServerDatabase.cs b/Oqtane.Server/Databases/SqlServerDatabase.cs index 5b33d3cd..d7d885c5 100644 --- a/Oqtane.Server/Databases/SqlServerDatabase.cs +++ b/Oqtane.Server/Databases/SqlServerDatabase.cs @@ -1,17 +1,61 @@ -using Microsoft.EntityFrameworkCore; -using Oqtane.Interfaces; +using System; +using System.Collections.Generic; +using Oqtane.Models; +using Oqtane.Repository.Databases; -namespace Oqtane.Repository.Databases +// ReSharper disable ArrangeObjectCreationWhenTypeNotEvident + +namespace Oqtane.Databases { - public class SqlServerDatabase : IDatabase + public class SqlServerDatabase : SqlServerDatabaseBase { - public string FriendlyName => "SQL Server"; + private static string _friendlyName => "SQL Server"; + private static string _name => "SqlServer"; - public string Name => "SqlServer"; - - public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + private static readonly List _connectionStringFields = new() { - return optionsBuilder.UseSqlServer(connectionString); + new() {Name = "Server", FriendlyName = "Server", Value = "."}, + new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}"}, + new() {Name = "IntegratedSecurity", FriendlyName = "Integrated Security", Value = "true"}, + new() {Name = "Uid", FriendlyName = "User Id", Value = ""}, + new() {Name = "Pwd", FriendlyName = "Password", Value = ""} + }; + + public SqlServerDatabase() :base(_name, _friendlyName, _connectionStringFields) { } + + public override string BuildConnectionString() + { + var connectionString = String.Empty; + + var server = ConnectionStringFields[0].Value; + var database = ConnectionStringFields[1].Value; + var integratedSecurity = Boolean.Parse(ConnectionStringFields[2].Value); + var userId = ConnectionStringFields[3].Value; + var password = ConnectionStringFields[4].Value; + + if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database)) + { + connectionString = $"Data Source={server};Initial Catalog={database};"; + } + + if (integratedSecurity) + { + connectionString += "Integrated Security=SSPI;"; + } + else + { + if (!String.IsNullOrEmpty(userId) && !String.IsNullOrEmpty(password)) + { + connectionString += $"User ID={userId};Password={password};"; + } + else + { + connectionString = String.Empty; + } + } + + return connectionString; + } } } diff --git a/Oqtane.Server/Databases/SqlServerDatabaseBase.cs b/Oqtane.Server/Databases/SqlServerDatabaseBase.cs new file mode 100644 index 00000000..151f6837 --- /dev/null +++ b/Oqtane.Server/Databases/SqlServerDatabaseBase.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; +using Oqtane.Models; + +namespace Oqtane.Repository.Databases +{ + public abstract class SqlServerDatabaseBase : IOqtaneDatabase + { + protected SqlServerDatabaseBase(string name, string friendlyName, List connectionStringFields) + { + Name = name; + FriendlyName = friendlyName; + ConnectionStringFields = connectionStringFields; + } + + public string FriendlyName { get; } + + public string Name { get; } + + public string Provider => "Microsoft.EntityFrameworkCore.SqlServer"; + + public List ConnectionStringFields { get; } + + public OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) + { + return table.Column(name: name, nullable: false).Annotation("SqlServer:Identity", "1, 1"); + } + + public abstract string BuildConnectionString(); + + public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + return optionsBuilder.UseSqlServer(connectionString); + } + } +} diff --git a/Oqtane.Server/Databases/SqliteDatabase.cs b/Oqtane.Server/Databases/SqliteDatabase.cs deleted file mode 100644 index 4ac9a756..00000000 --- a/Oqtane.Server/Databases/SqliteDatabase.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Oqtane.Interfaces; - -namespace Oqtane.Repository.Databases -{ - public class SqliteDatabase : IDatabase - { - public string FriendlyName => Name; - - public string Name => "Sqlite"; - - public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) - { - return optionsBuilder.UseSqlite(connectionString); - } - } -} diff --git a/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs b/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs index e9c53a1b..41aa1de8 100644 --- a/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs @@ -1,8 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Oqtane.Interfaces; // ReSharper disable ConvertToUsingDeclaration @@ -10,14 +8,22 @@ namespace Oqtane.Extensions { public static class DbContextOptionsBuilderExtensions { + public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, IOqtaneDatabase database, string connectionString) + { + database.UseDatabase(optionsBuilder, connectionString); + + return optionsBuilder; + } + public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, string databaseType, string connectionString) { var type = Type.GetType(databaseType); - var database = Activator.CreateInstance(type) as IDatabase; + var database = Activator.CreateInstance(type) as IOqtaneDatabase; database.UseDatabase(optionsBuilder, connectionString); return optionsBuilder; } + } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index bf1064b3..68306de5 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -48,12 +48,12 @@ namespace Microsoft.Extensions.DependencyInjection } // dynamically register database providers - var databaseTypes = assembly.GetInterfaces(); + var databaseTypes = assembly.GetInterfaces(); foreach (var databaseType in databaseTypes) { if (databaseType.AssemblyQualifiedName != null) { - var serviceType = Type.GetType("Oqtane.Interfaces.IDatabase, Oqtane.Shared"); + var serviceType = Type.GetType("Oqtane.Interfaces.IOqtaneDatabase, Oqtane.Shared"); services.AddScoped(serviceType ?? databaseType, databaseType); } } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index f91da21d..bad8c272 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -13,6 +13,7 @@ using Oqtane.Models; using Oqtane.Repository; using Oqtane.Shared; using Oqtane.Enums; +using Oqtane.Interfaces; using File = System.IO.File; // ReSharper disable MemberCanBePrivate.Global @@ -172,11 +173,16 @@ namespace Oqtane.Infrastructure var connectionString = NormalizeConnectionString(install.ConnectionString); var databaseType = install.DatabaseType; - using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(databaseType, connectionString).Options)) + using (var scope = _serviceScopeFactory.CreateScope()) { - // create empty database if it does not exist - dbc.Database.EnsureCreated(); - result.Success = true; + var databases = scope.ServiceProvider.GetServices(); + + using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(databases.Single(d => d.Name == databaseType), connectionString).Options)) + { + // create empty database if it does not exist + dbc.Database.EnsureCreated(); + result.Success = true; + } } } catch (Exception ex) @@ -198,26 +204,31 @@ namespace Oqtane.Infrastructure if (install.TenantName == TenantNames.Master) { - try + using (var scope = _serviceScopeFactory.CreateScope()) { - var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString, DatabaseType = install.DatabaseType}; + var databases = scope.ServiceProvider.GetServices(); - using (var masterDbContext = new MasterDBContext(new DbContextOptions(), dbConfig)) + try { - // Push latest model into database - masterDbContext.Database.Migrate(); - result.Success = true; - } - } - catch (Exception ex) - { - result.Message = ex.Message; - } + var dbConfig = new DbConfig(null, null, databases) {ConnectionString = install.ConnectionString, DatabaseType = install.DatabaseType}; - if (result.Success) - { - UpdateConnectionString(install.ConnectionString); - UpdateDatabaseType(install.DatabaseType); + using (var masterDbContext = new MasterDBContext(new DbContextOptions(), dbConfig)) + { + // Push latest model into database + masterDbContext.Database.Migrate(); + result.Success = true; + } + } + catch (Exception ex) + { + result.Message = ex.Message; + } + + if (result.Success) + { + UpdateConnectionString(install.ConnectionString); + UpdateDatabaseType(install.DatabaseType); + } } } else @@ -234,38 +245,56 @@ namespace Oqtane.Infrastructure if (!string.IsNullOrEmpty(install.TenantName) && !string.IsNullOrEmpty(install.Aliases)) { - using (var db = GetInstallationContext()) + using (var scope = _serviceScopeFactory.CreateScope()) { - Tenant tenant; - if (install.IsNewTenant) - { - tenant = new Tenant { Name = install.TenantName, - DBConnectionString = DenormalizeConnectionString(install.ConnectionString), - DBType = install.DatabaseType, - CreatedBy = "", - CreatedOn = DateTime.UtcNow, - ModifiedBy = "", - ModifiedOn = DateTime.UtcNow }; - db.Tenant.Add(tenant); - db.SaveChanges(); - _cache.Remove("tenants"); - } - else - { - tenant = db.Tenant.FirstOrDefault(item => item.Name == install.TenantName); - } + var databases = scope.ServiceProvider.GetServices(); - foreach (var aliasName in install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + using (var db = GetInstallationContext(databases)) { - if (tenant != null) + Tenant tenant; + if (install.IsNewTenant) { - var alias = new Alias { Name = aliasName, TenantId = tenant.TenantId, SiteId = -1, CreatedBy = "", CreatedOn = DateTime.UtcNow, ModifiedBy = "", ModifiedOn = DateTime.UtcNow }; - db.Alias.Add(alias); + tenant = new Tenant + { + Name = install.TenantName, + DBConnectionString = DenormalizeConnectionString(install.ConnectionString), + DBType = install.DatabaseType, + CreatedBy = "", + CreatedOn = DateTime.UtcNow, + ModifiedBy = "", + ModifiedOn = DateTime.UtcNow + }; + db.Tenant.Add(tenant); + db.SaveChanges(); + _cache.Remove("tenants"); + } + else + { + tenant = db.Tenant.FirstOrDefault(item => item.Name == install.TenantName); } - db.SaveChanges(); + foreach (var aliasName in install.Aliases.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)) + { + if (tenant != null) + { + var alias = new Alias + { + Name = aliasName, + TenantId = tenant.TenantId, + SiteId = -1, + CreatedBy = "", + CreatedOn = DateTime.UtcNow, + ModifiedBy = "", + ModifiedOn = DateTime.UtcNow + }; + db.Alias.Add(alias); + } + + db.SaveChanges(); + } + + _cache.Remove("aliases"); } - _cache.Remove("aliases"); } } @@ -274,12 +303,12 @@ namespace Oqtane.Infrastructure return result; } - private InstallationContext GetInstallationContext() + private InstallationContext GetInstallationContext(IEnumerable databases) { var databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey]; var connectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)); - return new InstallationContext(databaseType, connectionString); + return new InstallationContext(databases.Single(d => d.Name == databaseType), connectionString); } private Installation MigrateTenants(InstallConfig install) @@ -291,14 +320,15 @@ namespace Oqtane.Infrastructure using (var scope = _serviceScopeFactory.CreateScope()) { var upgrades = scope.ServiceProvider.GetRequiredService(); + var databases = scope.ServiceProvider.GetServices(); - using (var db = GetInstallationContext()) + using (var db = GetInstallationContext(databases)) { foreach (var tenant in db.Tenant.ToList()) { try { - var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString, DatabaseType = install.DatabaseType}; + var dbConfig = new DbConfig(null, null, databases) {ConnectionString = install.ConnectionString, DatabaseType = install.DatabaseType}; using (var tenantDbContext = new TenantDBContext(dbConfig, null)) { // Push latest model into database @@ -345,6 +375,8 @@ namespace Oqtane.Infrastructure { var moduleDefinitions = scope.ServiceProvider.GetRequiredService(); var sql = scope.ServiceProvider.GetRequiredService(); + var databases = scope.ServiceProvider.GetServices(); + foreach (var moduleDefinition in moduleDefinitions.GetModuleDefinitions()) { if (!string.IsNullOrEmpty(moduleDefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduleDefinition.ServerManagerType)) @@ -353,7 +385,7 @@ namespace Oqtane.Infrastructure if (moduleType != null) { var versions = moduleDefinition.ReleaseVersions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - using (var db = GetInstallationContext()) + using (var db = GetInstallationContext(databases)) { foreach (var tenant in db.Tenant.ToList()) { diff --git a/Oqtane.Server/Migrations/01000000_InitializeMaster.cs b/Oqtane.Server/Migrations/01000000_InitializeMaster.cs index 0465e058..064cda71 100644 --- a/Oqtane.Server/Migrations/01000000_InitializeMaster.cs +++ b/Oqtane.Server/Migrations/01000000_InitializeMaster.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Migrations.Extensions; using Oqtane.Repository; @@ -9,52 +11,57 @@ namespace Oqtane.Migrations { [DbContext(typeof(MasterDBContext))] [Migration("Master.01.00.00.00")] - public class InitializeMaster : Migration + public class InitializeMaster : MultiDatabaseMigration { + public InitializeMaster(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Create Tenant table - var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder); + var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase); tenantEntityBuilder.Create(); //Create Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.Create(); //Create ModuleDefinitions Table - var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder); + var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder, ActiveDatabase); moduleDefinitionsEntityBuilder.Create(); //Create Job Table - var jobEntityBuilder = new JobEntityBuilder(migrationBuilder); + var jobEntityBuilder = new JobEntityBuilder(migrationBuilder, ActiveDatabase); jobEntityBuilder.Create(); //Create JobLog Table - var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder); + var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder, ActiveDatabase); jobLogEntityBuilder.Create(); } protected override void Down(MigrationBuilder migrationBuilder) { //Drop Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.Drop(); //Drop JobLog Table - var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder); + var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder, ActiveDatabase); jobLogEntityBuilder.Drop(); //Drop Tenant table - var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder); + var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase); tenantEntityBuilder.Drop(); //Drop ModuleDefinitions Table - var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder); + var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder, ActiveDatabase); moduleDefinitionsEntityBuilder.Drop(); //Drop Job Table - var jobEntityBuilder = new JobEntityBuilder(migrationBuilder); + var jobEntityBuilder = new JobEntityBuilder(migrationBuilder, ActiveDatabase); jobEntityBuilder.Drop(); } + } } diff --git a/Oqtane.Server/Migrations/01000000_InitializeTenant.cs b/Oqtane.Server/Migrations/01000000_InitializeTenant.cs index fe1b8b1e..4d8817fa 100644 --- a/Oqtane.Server/Migrations/01000000_InitializeTenant.cs +++ b/Oqtane.Server/Migrations/01000000_InitializeTenant.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -8,86 +10,90 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.01.00.00.00")] - public class InitializeTenant : Migration + public class InitializeTenant : MultiDatabaseMigration { + public InitializeTenant(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Create Site table - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.Create(); //Create Page table - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.Create(); pageEntityBuilder.AddIndex("IX_Page", new [] {"SiteId", "Path", "UserId"}, true); //Add Column to Page table (for Sql Server only) we will drop it later for Sql Server only - if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer") + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") { pageEntityBuilder.AddBooleanColumn("EditMode"); } //Create Module table - var moduleEntityBuilder = new ModuleEntityBuilder(migrationBuilder); + var moduleEntityBuilder = new ModuleEntityBuilder(migrationBuilder, ActiveDatabase); moduleEntityBuilder.Create(); //Create PageModule table - var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder); + var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase); pageModuleEntityBuilder.Create(); //Create User table - var userEntityBuilder = new UserEntityBuilder(migrationBuilder); + var userEntityBuilder = new UserEntityBuilder(migrationBuilder, ActiveDatabase); userEntityBuilder.Create(); userEntityBuilder.AddIndex("IX_User", "Username", true); //Create Role table - var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder); + var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder, ActiveDatabase); roleEntityBuilder.Create(); //Create UserRole table - var userRoleEntityBuilder = new UserRoleEntityBuilder(migrationBuilder); + var userRoleEntityBuilder = new UserRoleEntityBuilder(migrationBuilder, ActiveDatabase); userRoleEntityBuilder.Create(); userRoleEntityBuilder.AddIndex("IX_UserRole", new [] {"RoleId", "UserId"}, true); //Create Permission table - var permissionEntityBuilder = new PermissionEntityBuilder(migrationBuilder); + var permissionEntityBuilder = new PermissionEntityBuilder(migrationBuilder, ActiveDatabase); permissionEntityBuilder.Create(); permissionEntityBuilder.AddIndex("IX_Permission", new [] {"SiteId", "EntityName", "EntityId", "PermissionName", "RoleId", "UserId"}, true); //Create Setting table - var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder); + var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); settingEntityBuilder.Create(); settingEntityBuilder.AddIndex("IX_Setting", new [] {"EntityName", "EntityId", "SettingName"}, true); //Create Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.Create(); //Create Log table - var logEntityBuilder = new LogEntityBuilder(migrationBuilder); + var logEntityBuilder = new LogEntityBuilder(migrationBuilder, ActiveDatabase); logEntityBuilder.Create(); //Create Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.Create(); //Create Folder table - var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder); + var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); folderEntityBuilder.Create(); folderEntityBuilder.AddIndex("IX_Folder", new [] {"SiteId", "Path"}, true); //Create File table - var fileEntityBuilder = new FileEntityBuilder(migrationBuilder); + var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); fileEntityBuilder.Create(); //Create AspNetUsers table - var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder); + var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder, ActiveDatabase); aspNetUsersEntityBuilder.Create(); aspNetUsersEntityBuilder.AddIndex("EmailIndex", "NormalizedEmail", true); aspNetUsersEntityBuilder.AddIndex("UserNameIndex", "NormalizedUserName", true); //Create AspNetUserClaims table - var aspNetUserClaimsEntityBuilder = new AspNetUserClaimsEntityBuilder(migrationBuilder); + var aspNetUserClaimsEntityBuilder = new AspNetUserClaimsEntityBuilder(migrationBuilder, ActiveDatabase); aspNetUserClaimsEntityBuilder.Create(); aspNetUserClaimsEntityBuilder.AddIndex("IX_AspNetUserClaims_UserId", "UserId", true); @@ -96,67 +102,67 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Drop AspNetUserClaims table - var aspNetUserClaimsEntityBuilder = new AspNetUserClaimsEntityBuilder(migrationBuilder); + var aspNetUserClaimsEntityBuilder = new AspNetUserClaimsEntityBuilder(migrationBuilder, ActiveDatabase); aspNetUserClaimsEntityBuilder.Drop(); //Drop AspNetUsers table - var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder); + var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder, ActiveDatabase); aspNetUsersEntityBuilder.Drop(); //Drop File table - var fileEntityBuilder = new FileEntityBuilder(migrationBuilder); + var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); fileEntityBuilder.Drop(); //Drop Folder table - var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder); + var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); folderEntityBuilder.Drop(); //Drop Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.Drop(); //Drop Log table - var logEntityBuilder = new LogEntityBuilder(migrationBuilder); + var logEntityBuilder = new LogEntityBuilder(migrationBuilder, ActiveDatabase); logEntityBuilder.Drop(); //Drop Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.Drop(); //Drop Setting table - var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder); + var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); settingEntityBuilder.Drop(); //Drop Permission table - var permissionEntityBuilder = new PermissionEntityBuilder(migrationBuilder); + var permissionEntityBuilder = new PermissionEntityBuilder(migrationBuilder, ActiveDatabase); permissionEntityBuilder.Drop(); //Drop UserRole table - var userRoleEntityBuilder = new UserRoleEntityBuilder(migrationBuilder); + var userRoleEntityBuilder = new UserRoleEntityBuilder(migrationBuilder, ActiveDatabase); userRoleEntityBuilder.Drop(); //Drop Role table - var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder); + var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder, ActiveDatabase); roleEntityBuilder.Drop(); //Drop User table - var userEntityBuilder = new UserEntityBuilder(migrationBuilder); + var userEntityBuilder = new UserEntityBuilder(migrationBuilder, ActiveDatabase); userEntityBuilder.Drop(); //Drop PageModule table - var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder); + var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase); pageModuleEntityBuilder.Drop(); //Drop Module table - var moduleEntityBuilder = new ModuleEntityBuilder(migrationBuilder); + var moduleEntityBuilder = new ModuleEntityBuilder(migrationBuilder, ActiveDatabase); moduleEntityBuilder.Drop(); //Drop Page table - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.Drop(); //Drop Site table - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.Drop(); } } diff --git a/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInMaster.cs b/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInMaster.cs index 7257bbb1..a1ab6525 100644 --- a/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInMaster.cs +++ b/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInMaster.cs @@ -1,5 +1,7 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,43 +9,47 @@ namespace Oqtane.Migrations { [DbContext(typeof(MasterDBContext))] [Migration("Master.01.00.01.00")] - public class AddAdditionalIndexesInMaster : Migration + public class AddAdditionalIndexesInMaster : MultiDatabaseMigration { + public AddAdditionalIndexesInMaster(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Update Tenant table - var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder); + var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase); tenantEntityBuilder.AddIndex("IX_Tenant", "Name"); //Update Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.AddIndex("IX_Alias", "Name"); //Update ModuleDefinitions Table - var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder); + var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder, ActiveDatabase); moduleDefinitionsEntityBuilder.AddIndex("IX_ModuleDefinition", "ModuleDefinitionName"); //Update Job Table - var jobEntityBuilder = new JobEntityBuilder(migrationBuilder); + var jobEntityBuilder = new JobEntityBuilder(migrationBuilder, ActiveDatabase); jobEntityBuilder.AddIndex("IX_Job", "JobType"); } protected override void Down(MigrationBuilder migrationBuilder) { //Update Tenant table - var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder); + var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase); tenantEntityBuilder.DropIndex("IX_Tenant"); //Update Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.DropIndex("IX_Alias"); //Update ModuleDefinitions Table - var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder); + var moduleDefinitionsEntityBuilder = new ModuleDefinitionsEntityBuilder(migrationBuilder, ActiveDatabase); moduleDefinitionsEntityBuilder.DropIndex("IX_ModuleDefinition"); //Update Job Table - var jobEntityBuilder = new JobEntityBuilder(migrationBuilder); + var jobEntityBuilder = new JobEntityBuilder(migrationBuilder, ActiveDatabase); jobEntityBuilder.DropIndex("IX_Job"); } } diff --git a/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInTenant.cs b/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInTenant.cs index 158c8b0f..3801cc3e 100644 --- a/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInTenant.cs +++ b/Oqtane.Server/Migrations/01000100_AddAdditionalIndexesInTenant.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Migrations.Extensions; using Oqtane.Repository; @@ -8,28 +10,32 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.01.00.01.00")] - public class AddAdditionalIndexesInTenant : Migration + public class AddAdditionalIndexesInTenant : MultiDatabaseMigration { + public AddAdditionalIndexesInTenant(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Create Index on Site - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.AddIndex("IX_Site", new [] {"TenantId", "Name"}, true); //Create Index on Role table - var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder); + var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder, ActiveDatabase); roleEntityBuilder.AddIndex("IX_Role", new [] {"SiteId", "Name"}, true); //Create Index on Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.AddIndex("IX_Profile", new [] {"SiteId", "Name"}, true); //Create Index on File table - var fileEntityBuilder = new FileEntityBuilder(migrationBuilder); + var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); fileEntityBuilder.AddIndex("IX_File", new [] {"FolderId", "Name"}, true); //Add Columns to Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.AddStringColumn("FromDisplayName", 50, true); notificationEntityBuilder.AddStringColumn("FromEmail", 256, true); notificationEntityBuilder.AddStringColumn("ToDisplayName", 50, true); @@ -38,27 +44,26 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Drop Index on Site table - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.DropIndex("IX_Site"); //Drop Index on Role table - var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder); + var roleEntityBuilder = new RoleEntityBuilder(migrationBuilder, ActiveDatabase); roleEntityBuilder.DropIndex("IX_Role"); //Drop Index on Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.DropIndex("IX_Profile"); //Drop Index on File table - var fileEntityBuilder = new FileEntityBuilder(migrationBuilder); + var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); fileEntityBuilder.DropIndex("IX_File"); //Drop Columns from Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.DropColumn("FromDisplayName"); notificationEntityBuilder.DropColumn("FromEmail"); notificationEntityBuilder.DropColumn("ToDisplayName"); } - } } diff --git a/Oqtane.Server/Migrations/01000101_AddAdditionColumnToNotifications.cs b/Oqtane.Server/Migrations/01000101_AddAdditionColumnToNotifications.cs index 7d01d0b0..1de51146 100644 --- a/Oqtane.Server/Migrations/01000101_AddAdditionColumnToNotifications.cs +++ b/Oqtane.Server/Migrations/01000101_AddAdditionColumnToNotifications.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,12 +9,16 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.01.00.01.01")] - public class AddAdditionColumnToNotifications : Migration + public class AddAdditionColumnToNotifications : MultiDatabaseMigration { + public AddAdditionColumnToNotifications(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Add Column to Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.AddDateTimeColumn("SendOn", true); migrationBuilder.Sql( @@ -26,7 +32,7 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Drop Column from Notification table - var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder); + var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase); notificationEntityBuilder.DropColumn("SendOn"); } } diff --git a/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs b/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs index 9ee79ff7..5f5fee65 100644 --- a/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs +++ b/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,14 +9,18 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.01.00.02.01")] - public class DropColumnFromPage : Migration + public class DropColumnFromPage : MultiDatabaseMigration { + public DropColumnFromPage(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Drop Column from Page table - if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer") + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") { - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropColumn("EditMode"); } } @@ -22,7 +28,7 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Add Column to Page table - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.AddBooleanColumn("EditMode"); } } diff --git a/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs b/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs index 79555898..6546e71a 100644 --- a/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs +++ b/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,25 +9,28 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.02.00.00.01")] - public class AddColumnToProfileAndUpdatePage : Migration + public class AddColumnToProfileAndUpdatePage : MultiDatabaseMigration { + public AddColumnToProfileAndUpdatePage(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Add Column to Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.AddStringColumn("Options", 2000, true); - ///Update new field migrationBuilder.Sql( @" UPDATE Profile SET Options = '' "); - //Alter Column in Page table - if (migrationBuilder.ActiveProvider != "Microsoft.EntityFrameworkCore.Sqlite") + //Alter Column in Page table for Sql Server + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") { - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropIndex("IX_Page"); pageEntityBuilder.AlterStringColumn("Path", 256); pageEntityBuilder.AddIndex("IX_Page", new [] {"SiteId", "Path", "UserId"}, true); @@ -35,13 +40,13 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Drop Column from Profile table - var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder); + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); profileEntityBuilder.DropColumn("Options"); //Alter Column in Page table - if (migrationBuilder.ActiveProvider != "Microsoft.EntityFrameworkCore.Sqlite") + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") { - var pageEntityBuilder = new PageEntityBuilder(migrationBuilder); + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropIndex("IX_Page"); pageEntityBuilder.AlterStringColumn("Path", 50); pageEntityBuilder.AddIndex("IX_Page", new [] {"SiteId", "Path", "UserId"}, true); diff --git a/Oqtane.Server/Migrations/02000101_UpdateIconColumnInPage.cs b/Oqtane.Server/Migrations/02000101_UpdateIconColumnInPage.cs index d62220ea..2b3a9e77 100644 --- a/Oqtane.Server/Migrations/02000101_UpdateIconColumnInPage.cs +++ b/Oqtane.Server/Migrations/02000101_UpdateIconColumnInPage.cs @@ -1,20 +1,27 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Repository; namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.02.00.01.01")] - public class UpdateIconColumnInPage : Migration + public class UpdateIconColumnInPage : MultiDatabaseMigration { + public UpdateIconColumnInPage(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { ///Update Icon Field in Page migrationBuilder.Sql( @" - UPDATE [Page] - SET Icon = IIF(Icon <> '', 'oi oi-' + Icon, ''); + UPDATE Page + SET Icon = 'oi oi-' + Icon + WHERE Icon <> '' "); } } diff --git a/Oqtane.Server/Migrations/02000102_AddLanguageTable.cs b/Oqtane.Server/Migrations/02000102_AddLanguageTable.cs index 21514c31..0fa1b490 100644 --- a/Oqtane.Server/Migrations/02000102_AddLanguageTable.cs +++ b/Oqtane.Server/Migrations/02000102_AddLanguageTable.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,19 +9,23 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.02.00.01.02")] - public class AddLanguageTable : Migration + public class AddLanguageTable : MultiDatabaseMigration { + public AddLanguageTable(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Create Language table - var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder); + var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase); languageEntityBuilder.Create(); } protected override void Down(MigrationBuilder migrationBuilder) { //Drop Language table - var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder); + var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase); languageEntityBuilder.Drop(); } } diff --git a/Oqtane.Server/Migrations/02000103_UpdatePageAndAddColumnToSite.cs b/Oqtane.Server/Migrations/02000103_UpdatePageAndAddColumnToSite.cs index 3b098e3a..041f407a 100644 --- a/Oqtane.Server/Migrations/02000103_UpdatePageAndAddColumnToSite.cs +++ b/Oqtane.Server/Migrations/02000103_UpdatePageAndAddColumnToSite.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,12 +9,16 @@ namespace Oqtane.Migrations { [DbContext(typeof(TenantDBContext))] [Migration("Tenant.02.00.01.03")] - public class UpdatePageAndAddColumnToSite : Migration + public class UpdatePageAndAddColumnToSite : MultiDatabaseMigration { + public UpdatePageAndAddColumnToSite(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Add Column to Site table - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.AddStringColumn("AdminContainerType", 200, true); //Update new column @@ -25,8 +31,8 @@ namespace Oqtane.Migrations //Delete records from Page migrationBuilder.Sql( @" - DELETE FROM [Page] - WHERE Path = 'admin/tenants'; + DELETE FROM Page + WHERE Path = 'admin/tenants' "); } @@ -34,7 +40,7 @@ namespace Oqtane.Migrations protected override void Down(MigrationBuilder migrationBuilder) { //Drop Column from Site table - var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder); + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); siteEntityBuilder.DropColumn("AdminContainerType"); } } diff --git a/Oqtane.Server/Migrations/02010000_AddIndexesForForeignKeyInMaster.cs b/Oqtane.Server/Migrations/02010000_AddIndexesForForeignKeyInMaster.cs index bbbeb06c..5828f962 100644 --- a/Oqtane.Server/Migrations/02010000_AddIndexesForForeignKeyInMaster.cs +++ b/Oqtane.Server/Migrations/02010000_AddIndexesForForeignKeyInMaster.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,27 +9,31 @@ namespace Oqtane.Migrations { [DbContext(typeof(MasterDBContext))] [Migration("Master.02.01.00.00")] - public class AddIndexesForForeignKeyInMaster : Migration + public class AddIndexesForForeignKeyInMaster : MultiDatabaseMigration { + public AddIndexesForForeignKeyInMaster(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Update JobLog table - var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder); + var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder, ActiveDatabase); jobLogEntityBuilder.AddIndex("IX_JobLog_JobId", "JobId"); //Update Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.AddIndex("IX_Alias_TenantId", "TenantId"); } protected override void Down(MigrationBuilder migrationBuilder) { //Update JobLog table - var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder); + var jobLogEntityBuilder = new JobLogEntityBuilder(migrationBuilder, ActiveDatabase); jobLogEntityBuilder.DropIndex("IX_JobLog_JobId"); //Update Alias table - var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder); + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); aliasEntityBuilder.DropIndex("IX_Alias_TenantId"); } } diff --git a/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs b/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs index 9d76ada3..388e95d5 100644 --- a/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs +++ b/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; using Oqtane.Migrations.EntityBuilders; using Oqtane.Repository; @@ -7,21 +9,28 @@ namespace Oqtane.Migrations { [DbContext(typeof(MasterDBContext))] [Migration("Master.02.01.00.01")] - public class AddDatabaseTypeColumnToTenant : Migration + public class AddDatabaseTypeColumnToTenant : MultiDatabaseMigration { + public AddDatabaseTypeColumnToTenant(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Add Column to Site table - var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder); + var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase); tenantEntityBuilder.AddStringColumn("DBType", 200, true); - //Update new column - migrationBuilder.Sql( - @" + //Update new column if SqlServer (Other Databases will not have any records yet) + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + { + migrationBuilder.Sql(@" UPDATE Tenant - SET DBType = 'Oqtane.Repository.Databases.SqlServerDatabase, Oqtane.Server' + SET DBType = 'SqlServer' "); + } + } } } diff --git a/Oqtane.Server/Migrations/EntityBuilders/AliasEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/AliasEntityBuilder.cs index fad6bd1a..d2d35188 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/AliasEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/AliasEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Alias", x => x.AliasId); private readonly ForeignKey _tenantForeignKey = new("FK_Alias_Tenant", x => x.TenantId, "Tenant", "TenantId", ReferentialAction.Cascade); - public AliasEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public AliasEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override AliasEntityBuilder BuildTable(ColumnsBuilder table) { - AliasId = table.AddAutoIncrementColumn("AliasId"); + AliasId = ActiveDatabase.AddAutoIncrementColumn(table,"AliasId"); Name = table.AddStringColumn("Name", 200); TenantId = table.AddIntegerColumn("TenantId"); SiteId = table.AddIntegerColumn("SiteId"); diff --git a/Oqtane.Server/Migrations/EntityBuilders/AspNetUserClaimsEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/AspNetUserClaimsEntityBuilder.cs index a99c9067..1a6fffce 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/AspNetUserClaimsEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/AspNetUserClaimsEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_AspNetUserClaims", x => x.Id); private readonly ForeignKey _aspNetUsersForeignKey = new("FK_AspNetUserClaims_AspNetUsers_UserId", x => x.UserId, "AspNetUsers", "Id", ReferentialAction.Cascade); - public AspNetUserClaimsEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public AspNetUserClaimsEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override AspNetUserClaimsEntityBuilder BuildTable(ColumnsBuilder table) { - Id = table.AddAutoIncrementColumn("Id"); + Id = ActiveDatabase.AddAutoIncrementColumn(table,"Id"); UserId = table.AddStringColumn("UserId", 450); ClaimType = table.AddMaxStringColumn("ClaimType", true); ClaimValue = table.AddMaxStringColumn("ClaimValue", true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/AspNetUsersEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/AspNetUsersEntityBuilder.cs index e6ac3b45..9a071297 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/AspNetUsersEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/AspNetUsersEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "AspNetUsers"; private readonly PrimaryKey _primaryKey = new("PK_AspNetUsers", x => x.Id); - public AspNetUsersEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public AspNetUsersEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; diff --git a/Oqtane.Server/Migrations/EntityBuilders/AuditableBaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/AuditableBaseEntityBuilder.cs index 9f805d6e..f92bffcc 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/AuditableBaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/AuditableBaseEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders { public abstract class AuditableBaseEntityBuilder : BaseEntityBuilder where TEntityBuilder : BaseEntityBuilder { - protected AuditableBaseEntityBuilder(MigrationBuilder migrationBuilder) : base (migrationBuilder) + protected AuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base (migrationBuilder, database) { } diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index d58a88a2..078c74a7 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; namespace Oqtane.Migrations.EntityBuilders @@ -10,9 +11,10 @@ namespace Oqtane.Migrations.EntityBuilders { private readonly MigrationBuilder _migrationBuilder; - protected BaseEntityBuilder(MigrationBuilder migrationBuilder) + protected BaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) { _migrationBuilder = migrationBuilder; + ActiveDatabase = database; ForeignKeys = new List>(); } @@ -23,9 +25,10 @@ namespace Oqtane.Migrations.EntityBuilders { table.AddForeignKey(foreignKey); } - } + protected IOqtaneDatabase ActiveDatabase { get; } + protected abstract TEntityBuilder BuildTable(ColumnsBuilder table); protected string EntityTableName { get; init; } diff --git a/Oqtane.Server/Migrations/EntityBuilders/DeletableAuditableBaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/DeletableAuditableBaseEntityBuilder.cs index 81cdd9e6..e5bfac03 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/DeletableAuditableBaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/DeletableAuditableBaseEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders { public abstract class DeletableAuditableBaseEntityBuilder : AuditableBaseEntityBuilder where TEntityBuilder : BaseEntityBuilder { - protected DeletableAuditableBaseEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + protected DeletableAuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { } diff --git a/Oqtane.Server/Migrations/EntityBuilders/DeletableBaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/DeletableBaseEntityBuilder.cs index c9bba190..0fe98b66 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/DeletableBaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/DeletableBaseEntityBuilder.cs @@ -2,6 +2,7 @@ using System; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable MemberCanBePrivate.Global @@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders { public abstract class DeletableBaseEntityBuilder : BaseEntityBuilder where TEntityBuilder : BaseEntityBuilder { - protected DeletableBaseEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + protected DeletableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { } diff --git a/Oqtane.Server/Migrations/EntityBuilders/FileEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/FileEntityBuilder.cs index 695935a1..3eb95051 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/FileEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/FileEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_File", x => x.FileId); private readonly ForeignKey _folderForeignKey = new("FK_File_Folder", x => x.FolderId, "Folder", "FolderId", ReferentialAction.Cascade); - public FileEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public FileEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override FileEntityBuilder BuildTable(ColumnsBuilder table) { - FileId = table.AddAutoIncrementColumn("FileId"); + FileId = ActiveDatabase.AddAutoIncrementColumn(table,"FileId"); FolderId = table.AddIntegerColumn("FolderId"); Name = table.AddStringColumn("Name", 50); Extension = table.AddStringColumn("Extension", 50); diff --git a/Oqtane.Server/Migrations/EntityBuilders/FolderEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/FolderEntityBuilder.cs index d7d5f63d..8da9514e 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/FolderEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/FolderEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Folder", x => x.FolderId); private readonly ForeignKey _siteForeignKey = new("FK_Folder_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public FolderEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public FolderEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override FolderEntityBuilder BuildTable(ColumnsBuilder table) { - FolderId = table.AddAutoIncrementColumn("FolderId"); + FolderId = ActiveDatabase.AddAutoIncrementColumn(table,"FolderId"); SiteId = table.AddIntegerColumn("SiteId"); ParentId = table.AddIntegerColumn("ParentId", true); Name = table.AddStringColumn("Name", 50); diff --git a/Oqtane.Server/Migrations/EntityBuilders/JobEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/JobEntityBuilder.cs index 1cdda817..066468ef 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/JobEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/JobEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "Job"; private readonly PrimaryKey _primaryKey = new("PK_Job", x => x.JobId); - public JobEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public JobEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override JobEntityBuilder BuildTable(ColumnsBuilder table) { - JobId = table.AddAutoIncrementColumn("JobId"); + JobId = ActiveDatabase.AddAutoIncrementColumn(table,"JobId"); Name = table.AddStringColumn("Name", 200); JobType = table.AddStringColumn("JobType", 200); Frequency = table.AddStringColumn("Frequency", 1); diff --git a/Oqtane.Server/Migrations/EntityBuilders/JobLogEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/JobLogEntityBuilder.cs index e26c1f44..d4082706 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/JobLogEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/JobLogEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_JobLog", x => x.JobLogId); private readonly ForeignKey _jobLogForeignKey = new("FK_JobLog_Job", x => x.JobId, "Job", "JobId", ReferentialAction.Cascade); - public JobLogEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public JobLogEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -22,7 +23,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override JobLogEntityBuilder BuildTable(ColumnsBuilder table) { - JobLogId = table.AddAutoIncrementColumn("JobLogId"); + JobLogId = ActiveDatabase.AddAutoIncrementColumn(table,"JobLogId"); JobId = table.AddIntegerColumn("JobId"); StartDate = table.AddDateTimeColumn("StartDate"); FinishDate = table.AddDateTimeColumn("FinishDate", true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/LanguageEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/LanguageEntityBuilder.cs index b32e07ec..8cf622a3 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/LanguageEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/LanguageEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Language", x => x.LanguageId); private readonly ForeignKey _siteForeignKey = new("FK_Language_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public LanguageEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public LanguageEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override LanguageEntityBuilder BuildTable(ColumnsBuilder table) { - LanguageId = table.AddAutoIncrementColumn("LanguageId"); + LanguageId = ActiveDatabase.AddAutoIncrementColumn(table,"LanguageId"); SiteId = table.AddIntegerColumn("SiteId"); Name = table.AddStringColumn("Name", 100); Code = table.AddStringColumn("Code", 10); diff --git a/Oqtane.Server/Migrations/EntityBuilders/LogEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/LogEntityBuilder.cs index 933e1256..e1a8ad33 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/LogEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/LogEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Log", x => x.LogId); private readonly ForeignKey _siteForeignKey = new("FK_Log_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public LogEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public LogEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override LogEntityBuilder BuildTable(ColumnsBuilder table) { - LogId = table.AddAutoIncrementColumn("LogId"); + LogId = ActiveDatabase.AddAutoIncrementColumn(table,"LogId"); SiteId = table.AddIntegerColumn("SiteId", true); LogDate = table.AddDateTimeColumn("LogDate"); PageId = table.AddIntegerColumn("PageId", true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/ModuleDefinitionsEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/ModuleDefinitionsEntityBuilder.cs index 5e7d5b50..d4891453 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/ModuleDefinitionsEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/ModuleDefinitionsEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "ModuleDefinition"; private readonly PrimaryKey _primaryKey = new("PK_ModuleDefinition", x => x.ModuleDefinitionId); - public ModuleDefinitionsEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public ModuleDefinitionsEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override ModuleDefinitionsEntityBuilder BuildTable(ColumnsBuilder table) { - ModuleDefinitionId = table.AddAutoIncrementColumn("ModuleDefinitionId"); + ModuleDefinitionId = ActiveDatabase.AddAutoIncrementColumn(table,"ModuleDefinitionId"); ModuleDefinitionName = table.AddStringColumn("ModuleDefinitionName", 200); Name = table.AddStringColumn("Name", 200, true); Description = table.AddStringColumn("Description", 2000, true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/ModuleEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/ModuleEntityBuilder.cs index 96f8b270..2bda7316 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/ModuleEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/ModuleEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Module", x => x.ModuleId); private readonly ForeignKey _siteForeignKey = new("FK_Module_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public ModuleEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public ModuleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override ModuleEntityBuilder BuildTable(ColumnsBuilder table) { - ModuleId = table.AddAutoIncrementColumn("ModuleId"); + ModuleId = ActiveDatabase.AddAutoIncrementColumn(table,"ModuleId"); SiteId = table.AddIntegerColumn("SiteId"); ModuleDefinitionName = table.AddStringColumn("ModuleDefinitionName", 200); AllPages = table.AddBooleanColumn("AllPages"); diff --git a/Oqtane.Server/Migrations/EntityBuilders/NotificationEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/NotificationEntityBuilder.cs index 2ee3779b..f3866af9 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/NotificationEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/NotificationEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Notification", x => x.NotificationId); private readonly ForeignKey _siteForeignKey = new("FK_Notification_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public NotificationEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public NotificationEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override NotificationEntityBuilder BuildTable(ColumnsBuilder table) { - NotificationId = table.AddAutoIncrementColumn("NotificationId"); + NotificationId = ActiveDatabase.AddAutoIncrementColumn(table,"NotificationId"); SiteId = table.AddIntegerColumn("SiteId"); FromUserId = table.AddIntegerColumn("FromUserId", true); ToUserId = table.AddIntegerColumn("ToUserId", true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs index c259b945..ff1d57a3 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Page", x => x.PageId); private readonly ForeignKey _siteForeignKey = new("FK_Page_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public PageEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public PageEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,9 +24,16 @@ namespace Oqtane.Migrations.EntityBuilders protected override PageEntityBuilder BuildTable(ColumnsBuilder table) { - PageId = table.AddAutoIncrementColumn("PageId"); + PageId = ActiveDatabase.AddAutoIncrementColumn(table,"PageId"); SiteId = table.AddIntegerColumn("SiteId"); - Path = table.AddStringColumn("Path", 50); + if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + { + Path = table.AddStringColumn("Path", 50); + } + else + { + Path = table.AddStringColumn("Path", 256); + } Name = table.AddStringColumn("Name", 50); Title = table.AddStringColumn("Title", 200, true); ThemeType = table.AddStringColumn("ThemeType", 200, true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/PageModuleEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/PageModuleEntityBuilder.cs index ff9d0594..66fdd39f 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/PageModuleEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/PageModuleEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -15,7 +16,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly ForeignKey _moduleForeignKey = new("FK_PageModule_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.NoAction); private readonly ForeignKey _pageForeignKey = new("FK_PageModule_Page", x => x.PageId, "Page", "PageId", ReferentialAction.Cascade); - public PageModuleEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public PageModuleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -25,7 +26,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override PageModuleEntityBuilder BuildTable(ColumnsBuilder table) { - PageModuleId = table.AddAutoIncrementColumn("PageModuleId"); + PageModuleId = ActiveDatabase.AddAutoIncrementColumn(table,"PageModuleId"); PageId = table.AddIntegerColumn("PageId"); ModuleId = table.AddIntegerColumn("ModuleId"); Title = table.AddStringColumn("Title", 200); diff --git a/Oqtane.Server/Migrations/EntityBuilders/PermissionEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/PermissionEntityBuilder.cs index af383609..5636062b 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/PermissionEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/PermissionEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -16,7 +17,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly ForeignKey _userForeignKey = new("FK_Permission_User", x => x.UserId, "User", "UserId", ReferentialAction.NoAction); private readonly ForeignKey _roleForeignKey = new("FK_Permission_Role", x => x.RoleId, "Role", "RoleId", ReferentialAction.NoAction); - public PermissionEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public PermissionEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -27,7 +28,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override PermissionEntityBuilder BuildTable(ColumnsBuilder table) { - PermissionId = table.AddAutoIncrementColumn("PermissionId"); + PermissionId = ActiveDatabase.AddAutoIncrementColumn(table,"PermissionId"); SiteId = table.AddIntegerColumn("SiteId"); EntityName = table.AddStringColumn("EntityName", 50); EntityId = table.AddIntegerColumn("EntityId"); diff --git a/Oqtane.Server/Migrations/EntityBuilders/ProfileEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/ProfileEntityBuilder.cs index b5e27469..ca57a939 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/ProfileEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/ProfileEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Profile", x => x.ProfileId); private readonly ForeignKey _siteForeignKey = new("FK_Profile_Sites", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public ProfileEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public ProfileEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override ProfileEntityBuilder BuildTable(ColumnsBuilder table) { - ProfileId = table.AddAutoIncrementColumn("ProfileId"); + ProfileId = ActiveDatabase.AddAutoIncrementColumn(table,"ProfileId"); SiteId = table.AddIntegerColumn("SiteId", true); Name = table.AddStringColumn("Name", 50); Title = table.AddStringColumn("Title", 50); diff --git a/Oqtane.Server/Migrations/EntityBuilders/RoleEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/RoleEntityBuilder.cs index 67deafa1..dd9956d6 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/RoleEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/RoleEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_Role", x => x.RoleId); private readonly ForeignKey _siteForeignKey = new("FK_Role_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade); - public RoleEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public RoleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -23,7 +24,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override RoleEntityBuilder BuildTable(ColumnsBuilder table) { - RoleId = table.AddAutoIncrementColumn("RoleId"); + RoleId = ActiveDatabase.AddAutoIncrementColumn(table,"RoleId"); SiteId = table.AddIntegerColumn("SiteId", true); Name = table.AddStringColumn("Name", 256); Description = table.AddStringColumn("Description", 256); diff --git a/Oqtane.Server/Migrations/EntityBuilders/SettingEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/SettingEntityBuilder.cs index 7f4bb07d..31d32806 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/SettingEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/SettingEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "Setting"; private readonly PrimaryKey _primaryKey = new("PK_Setting", x => x.SettingId); - public SettingEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public SettingEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override SettingEntityBuilder BuildTable(ColumnsBuilder table) { - SettingId = table.AddAutoIncrementColumn("SettingId"); + SettingId = ActiveDatabase.AddAutoIncrementColumn(table,"SettingId"); EntityName = table.AddStringColumn("EntityName", 50); EntityId = table.AddIntegerColumn("EntityId"); SettingName = table.AddStringColumn("SettingName", 50); diff --git a/Oqtane.Server/Migrations/EntityBuilders/SiteEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/SiteEntityBuilder.cs index 172ff1df..c6773c4e 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/SiteEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/SiteEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "Site"; private readonly PrimaryKey _primaryKey = new("PK_Site", x => x.SiteId); - public SiteEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public SiteEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override SiteEntityBuilder BuildTable(ColumnsBuilder table) { - SiteId = table.AddAutoIncrementColumn("SiteId"); + SiteId = ActiveDatabase.AddAutoIncrementColumn(table,"SiteId"); TenantId = table.AddIntegerColumn("TenantId"); Name = table.AddStringColumn("Name", 200); LogoFileId = table.AddIntegerColumn("LogoFileId", true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/TenantEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/TenantEntityBuilder.cs index 1cf04a30..794fc2ac 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/TenantEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/TenantEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "Tenant"; private readonly PrimaryKey _primaryKey = new("PK_Tenant", x => x.TenantId); - public TenantEntityBuilder(MigrationBuilder migrationBuilder): base(migrationBuilder) + public TenantEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database): base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override TenantEntityBuilder BuildTable(ColumnsBuilder table) { - TenantId = table.AddAutoIncrementColumn("TenantId"); + TenantId = ActiveDatabase.AddAutoIncrementColumn(table,"TenantId"); Name = table.AddStringColumn("Name", 100); DBConnectionString = table.AddStringColumn("DBConnectionString", 1024); Version = table.AddStringColumn("Version", 50, true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/UserEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/UserEntityBuilder.cs index cfcf6acb..51a2b78e 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/UserEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/UserEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders private const string _entityTableName = "User"; private readonly PrimaryKey _primaryKey = new("PK_User", x => x.UserId); - public UserEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public UserEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -21,7 +22,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override UserEntityBuilder BuildTable(ColumnsBuilder table) { - UserId = table.AddAutoIncrementColumn("UserId"); + UserId = ActiveDatabase.AddAutoIncrementColumn(table,"UserId"); Username = table.AddStringColumn("Username", 256); DisplayName = table.AddStringColumn("DisplayName", 50); Email = table.AddStringColumn("Email", 256); diff --git a/Oqtane.Server/Migrations/EntityBuilders/UserRoleEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/UserRoleEntityBuilder.cs index 46ee993e..88327191 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/UserRoleEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/UserRoleEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations.Extensions; // ReSharper disable MemberCanBePrivate.Global @@ -15,7 +16,7 @@ namespace Oqtane.Migrations.EntityBuilders private readonly ForeignKey _userForeignKey = new("FK_UserRole_User", x => x.UserId, "User", "UserId", ReferentialAction.Cascade); private readonly ForeignKey _roleForeignKey = new("FK_UserRole_Role", x => x.RoleId, "Role", "RoleId", ReferentialAction.NoAction); - public UserRoleEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public UserRoleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -25,7 +26,7 @@ namespace Oqtane.Migrations.EntityBuilders protected override UserRoleEntityBuilder BuildTable(ColumnsBuilder table) { - UserRoleId = table.AddAutoIncrementColumn("UserRoleId"); + UserRoleId = ActiveDatabase.AddAutoIncrementColumn(table,"UserRoleId"); UserId = table.AddIntegerColumn("UserId"); RoleId = table.AddIntegerColumn("RoleId"); EffectiveDate = table.AddDateTimeColumn("EffectiveDate", true); diff --git a/Oqtane.Server/Migrations/Extensions/ColumnsBuilderExtensions.cs b/Oqtane.Server/Migrations/Extensions/ColumnsBuilderExtensions.cs index ecd272db..068a54ef 100644 --- a/Oqtane.Server/Migrations/Extensions/ColumnsBuilderExtensions.cs +++ b/Oqtane.Server/Migrations/Extensions/ColumnsBuilderExtensions.cs @@ -6,14 +6,6 @@ namespace Oqtane.Migrations.Extensions { public static class ColumnsBuilderExtensions { - public static OperationBuilder AddAutoIncrementColumn(this ColumnsBuilder table, string name) - { - return table.Column(name: name, nullable: false) - .Annotation("SqlServer:Identity", "1, 1") - .Annotation("Sqlite:Autoincrement", true) - .Annotation("MySql:ValueGeneratedOnAdd", true); - } - public static OperationBuilder AddBooleanColumn(this ColumnsBuilder table, string name, bool nullable = false) { return table.Column(name: name, nullable: nullable); @@ -36,12 +28,12 @@ namespace Oqtane.Migrations.Extensions public static OperationBuilder AddMaxStringColumn(this ColumnsBuilder table, string name, bool nullable = false) { - return table.Column(name: name, nullable: nullable); + return table.Column(name: name, nullable: nullable, unicode: true); } public static OperationBuilder AddStringColumn(this ColumnsBuilder table, string name, int length, bool nullable = false) { - return table.Column(name: name, maxLength: length, nullable: nullable); + return table.Column(name: name, maxLength: length, nullable: nullable, unicode: true); } } diff --git a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs new file mode 100644 index 00000000..2a0e6fce --- /dev/null +++ b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; + +namespace Oqtane.Migrations +{ + public abstract class MultiDatabaseMigration : Migration + { + private readonly IEnumerable _databases; + + protected MultiDatabaseMigration(IEnumerable databases) + { + _databases = databases; + } + + protected IOqtaneDatabase ActiveDatabase => _databases.FirstOrDefault(d => d.Provider == ActiveProvider); + } +} diff --git a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigrationsAssembly.cs b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigrationsAssembly.cs new file mode 100644 index 00000000..6373f351 --- /dev/null +++ b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigrationsAssembly.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Internal; +using Oqtane.Interfaces; +using Oqtane.Repository.Databases.Interfaces; + +namespace Oqtane.Migrations.Framework +{ + public class MultiDatabaseMigrationsAssembly: MigrationsAssembly + { + private readonly IEnumerable _databases; + + public MultiDatabaseMigrationsAssembly( + ICurrentDbContext currentContext, + IDbContextOptions options, + IMigrationsIdGenerator idGenerator, + IDiagnosticsLogger logger) + : base(currentContext, options, idGenerator, logger) + { + var multiDatabaseContext = currentContext.Context as IMultiDatabase; + if (multiDatabaseContext != null) _databases = multiDatabaseContext.Databases; + } + public override Migration CreateMigration(TypeInfo migrationClass, string activeProvider) + { + var hasCtorWithCacheOptions = migrationClass.GetConstructor(new[] { typeof(IEnumerable) }) != null; + + if (hasCtorWithCacheOptions) + { + var migration = (Migration)Activator.CreateInstance(migrationClass.AsType(), _databases); + if (migration != null) + { + migration.ActiveProvider = activeProvider; + return migration; + } + } + + return base.CreateMigration(migrationClass, activeProvider); + } + } +} diff --git a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs index 4329a4c7..96774c52 100644 --- a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs +++ b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Oqtane.Infrastructure; using Oqtane.Models; using Oqtane.Repository; @@ -8,6 +9,8 @@ using System.Net; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Oqtane.Enums; +using Oqtane.Interfaces; + // ReSharper disable ConvertToUsingDeclaration namespace Oqtane.Modules.HtmlText.Manager @@ -15,12 +18,12 @@ namespace Oqtane.Modules.HtmlText.Manager public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable { private readonly IHtmlTextRepository _htmlText; - private readonly ISqlRepository _sql; + private readonly IEnumerable _databases; - public HtmlTextManager(IHtmlTextRepository htmlText, ISqlRepository sql) + public HtmlTextManager(IHtmlTextRepository htmlText, IEnumerable databases) { _htmlText = htmlText; - _sql = sql; + _databases = databases; } public string ExportModule(Module module) @@ -54,13 +57,13 @@ namespace Oqtane.Modules.HtmlText.Manager public bool Install(Tenant tenant, string version) { - var dbConfig = new DbConfig(null, null) {ConnectionString = tenant.DBConnectionString, DatabaseType = tenant.DBType}; + var dbConfig = new DbConfig(null, null, _databases) {ConnectionString = tenant.DBConnectionString, DatabaseType = tenant.DBType}; return Migrate(new HtmlTextContext(dbConfig, null), tenant, MigrationType.Up); } public bool Uninstall(Tenant tenant) { - var dbConfig = new DbConfig(null, null) {ConnectionString = tenant.DBConnectionString, DatabaseType = tenant.DBType}; + var dbConfig = new DbConfig(null, null, _databases) {ConnectionString = tenant.DBConnectionString, DatabaseType = tenant.DBType}; return Migrate(new HtmlTextContext(dbConfig, null), tenant, MigrationType.Down); } } diff --git a/Oqtane.Server/Modules/HtmlText/Migrations/01000000_InitializeModule.cs b/Oqtane.Server/Modules/HtmlText/Migrations/01000000_InitializeModule.cs index 2214df2c..5ed5242c 100644 --- a/Oqtane.Server/Modules/HtmlText/Migrations/01000000_InitializeModule.cs +++ b/Oqtane.Server/Modules/HtmlText/Migrations/01000000_InitializeModule.cs @@ -1,5 +1,8 @@ +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Interfaces; +using Oqtane.Migrations; using Oqtane.Modules.HtmlText.Migrations.EntityBuilders; using Oqtane.Modules.HtmlText.Repository; @@ -7,19 +10,23 @@ namespace Oqtane.Modules.HtmlText.Migrations { [DbContext(typeof(HtmlTextContext))] [Migration("HtmlText.01.00.00.00")] - public class InitializeModule : Migration + public class InitializeModule : MultiDatabaseMigration { + public InitializeModule(IEnumerable databases) : base(databases) + { + } + protected override void Up(MigrationBuilder migrationBuilder) { //Create HtmlText table - var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder); + var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder, ActiveDatabase); entityBuilder.Create(); } protected override void Down(MigrationBuilder migrationBuilder) { //Drop HtmlText table - var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder); + var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder, ActiveDatabase); entityBuilder.Drop(); } } diff --git a/Oqtane.Server/Modules/HtmlText/Migrations/EntityBuilders/HtmlTextEntityBuilder.cs b/Oqtane.Server/Modules/HtmlText/Migrations/EntityBuilders/HtmlTextEntityBuilder.cs index 972c4c7d..8ed3e956 100644 --- a/Oqtane.Server/Modules/HtmlText/Migrations/EntityBuilders/HtmlTextEntityBuilder.cs +++ b/Oqtane.Server/Modules/HtmlText/Migrations/EntityBuilders/HtmlTextEntityBuilder.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Interfaces; using Oqtane.Migrations; using Oqtane.Migrations.EntityBuilders; using Oqtane.Migrations.Extensions; @@ -16,7 +17,7 @@ namespace Oqtane.Modules.HtmlText.Migrations.EntityBuilders private readonly PrimaryKey _primaryKey = new("PK_HtmlText", x => x.HtmlTextId); private readonly ForeignKey _moduleForeignKey = new("FK_HtmlText_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.Cascade); - public HtmlTextEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder) + public HtmlTextEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database) { EntityTableName = _entityTableName; PrimaryKey = _primaryKey; @@ -25,7 +26,7 @@ namespace Oqtane.Modules.HtmlText.Migrations.EntityBuilders protected override HtmlTextEntityBuilder BuildTable(ColumnsBuilder table) { - HtmlTextId = table.AddAutoIncrementColumn("HtmlTextId"); + HtmlTextId = ActiveDatabase.AddAutoIncrementColumn(table,"HtmlTextId"); ModuleId = table.AddIntegerColumn("ModuleId"); Content = table.AddMaxStringColumn("Content"); diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs index f4aaf48c..168667fd 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs @@ -1,18 +1,21 @@ -using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; using Oqtane.Modules.HtmlText.Models; using Oqtane.Repository; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; +using Oqtane.Interfaces; +using Oqtane.Repository.Databases.Interfaces; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global namespace Oqtane.Modules.HtmlText.Repository { - public class HtmlTextContext : DBContextBase, IService + public class HtmlTextContext : DBContextBase, IService, IMultiDatabase { - public virtual DbSet HtmlText { get; set; } - public HtmlTextContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) { - // ContextBase handles multi-tenant database connections } + + public virtual DbSet HtmlText { get; set; } } } diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index a87d0533..8898841a 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -50,7 +50,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -58,6 +57,9 @@ + + + diff --git a/Oqtane.Server/Repository/Context/DBContextBase.cs b/Oqtane.Server/Repository/Context/DBContextBase.cs index 5ee8b6c1..0e7b0289 100644 --- a/Oqtane.Server/Repository/Context/DBContextBase.cs +++ b/Oqtane.Server/Repository/Context/DBContextBase.cs @@ -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 Databases { get; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.ReplaceService(); + 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); diff --git a/Oqtane.Server/Repository/Context/DbConfig.cs b/Oqtane.Server/Repository/Context/DbConfig.cs index 7cc636ef..97e60f8f 100644 --- a/Oqtane.Server/Repository/Context/DbConfig.cs +++ b/Oqtane.Server/Repository/Context/DbConfig.cs @@ -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 databases) { Accessor = accessor; Configuration = configuration; + Databases = databases; } public IHttpContextAccessor Accessor { get; } public IConfiguration Configuration { get; } + public IEnumerable Databases { get; set; } + public string ConnectionString { get; set; } public string DatabaseType { get; set; } diff --git a/Oqtane.Server/Repository/Context/InstallationContext.cs b/Oqtane.Server/Repository/Context/InstallationContext.cs index 061aecbb..d64bd5f0 100644 --- a/Oqtane.Server/Repository/Context/InstallationContext.cs +++ b/Oqtane.Server/Repository/Context/InstallationContext.cs @@ -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 { get; set; } public virtual DbSet Tenant { get; set; } diff --git a/Oqtane.Server/Repository/Context/MasterDBContext.cs b/Oqtane.Server/Repository/Context/MasterDBContext.cs index 04f61176..a5040c33 100644 --- a/Oqtane.Server/Repository/Context/MasterDBContext.cs +++ b/Oqtane.Server/Repository/Context/MasterDBContext.cs @@ -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 options, IDbConfig dbConfig) : base(options) { _dbConfig = dbConfig; + Databases = dbConfig.Databases; } + public IEnumerable Databases { get; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.ReplaceService(); + 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); } diff --git a/Oqtane.Server/Repository/Context/TenantDBContext.cs b/Oqtane.Server/Repository/Context/TenantDBContext.cs index 3e2f5d3d..8aa6ccc2 100644 --- a/Oqtane.Server/Repository/Context/TenantDBContext.cs +++ b/Oqtane.Server/Repository/Context/TenantDBContext.cs @@ -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 { get; set; } public virtual DbSet Page { get; set; } public virtual DbSet PageModule { get; set; } @@ -21,13 +28,6 @@ namespace Oqtane.Repository public virtual DbSet Notification { get; set; } public virtual DbSet Folder { get; set; } public virtual DbSet File { get; set; } - public virtual DbSet Language { get; set; } - - public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) - { - // DBContextBase handles multi-tenant database connections - } - } } diff --git a/Oqtane.Server/Repository/Interfaces/IDbConfig.cs b/Oqtane.Server/Repository/Interfaces/IDbConfig.cs index cde50726..2d364505 100644 --- a/Oqtane.Server/Repository/Interfaces/IDbConfig.cs +++ b/Oqtane.Server/Repository/Interfaces/IDbConfig.cs @@ -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 Databases { get; set; } + public string ConnectionString { get; set; } + public string DatabaseType { get; set; } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 5ba2ff1b..60ae50b8 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -130,10 +130,6 @@ namespace Oqtane services.AddSingleton(); - services.AddScoped(); - services.AddDbContext(options => { }); - services.AddDbContext(options => { }); - services.AddIdentityCore(options => { }) .AddEntityFrameworkStores() .AddSignInManager() @@ -214,6 +210,10 @@ namespace Oqtane // load the external assemblies into the app domain, install services services.AddOqtane(_runtime, _supportedCultures); + services.AddScoped(); + services.AddDbContext(options => { }); + services.AddDbContext(options => { }); + services.AddMvc() .AddNewtonsoftJson() diff --git a/Oqtane.Shared/Interfaces/IDatabase.cs b/Oqtane.Shared/Interfaces/IDatabase.cs deleted file mode 100644 index 8a03d74b..00000000 --- a/Oqtane.Shared/Interfaces/IDatabase.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace Oqtane.Interfaces -{ - public interface IDatabase - { - public string FriendlyName { get; } - - public string Name { get; } - - public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString); - } -} diff --git a/Oqtane.Shared/Interfaces/IOqtaneDatabase.cs b/Oqtane.Shared/Interfaces/IOqtaneDatabase.cs new file mode 100644 index 00000000..7f214a40 --- /dev/null +++ b/Oqtane.Shared/Interfaces/IOqtaneDatabase.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Models; + +namespace Oqtane.Interfaces +{ + public interface IOqtaneDatabase + { + public string FriendlyName { get; } + + public string Name { get; } + + public string Provider { get; } + + public List ConnectionStringFields { get; } + + public OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name); + + public string BuildConnectionString(); + + public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString); + } +} diff --git a/Oqtane.Shared/Models/ConnectionStringField.cs b/Oqtane.Shared/Models/ConnectionStringField.cs new file mode 100644 index 00000000..a014168c --- /dev/null +++ b/Oqtane.Shared/Models/ConnectionStringField.cs @@ -0,0 +1,11 @@ +namespace Oqtane.Models +{ + public class ConnectionStringField + { + public string FriendlyName { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + } +} diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 44aaab47..7760da33 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -19,9 +19,16 @@ + + + + C:\Users\charl\.nuget\packages\microsoft.entityframeworkcore.relational\5.0.2\lib\netstandard2.1\Microsoft.EntityFrameworkCore.Relational.dll + + + diff --git a/Oqtane.sln b/Oqtane.sln index 70e85123..9548b9c6 100644 --- a/Oqtane.sln +++ b/Oqtane.sln @@ -20,6 +20,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oqtane.Database.MySQL", "Oqtane.Database.MySQL\Oqtane.Database.MySQL.csproj", "{A996FD2D-DAC8-4DFA-92B2-51DF32C6E014}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oqtane.Database.PostgreSQL", "Oqtane.Database.PostgreSQL\Oqtane.Database.PostgreSQL.csproj", "{3B29B35F-65E7-4819-9AED-EAC7FCFA309B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oqtane.Database.Sqlite", "Oqtane.Database.Sqlite\Oqtane.Database.Sqlite.csproj", "{E4F50CA9-19A6-465A-9469-C033748AD95B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,6 +52,18 @@ Global {823B556D-8D4E-4BB8-A65A-C4EB5E7E7424}.Debug|Any CPU.Build.0 = Debug|Any CPU {823B556D-8D4E-4BB8-A65A-C4EB5E7E7424}.Release|Any CPU.ActiveCfg = Release|Any CPU {823B556D-8D4E-4BB8-A65A-C4EB5E7E7424}.Release|Any CPU.Build.0 = Release|Any CPU + {A996FD2D-DAC8-4DFA-92B2-51DF32C6E014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A996FD2D-DAC8-4DFA-92B2-51DF32C6E014}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A996FD2D-DAC8-4DFA-92B2-51DF32C6E014}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A996FD2D-DAC8-4DFA-92B2-51DF32C6E014}.Release|Any CPU.Build.0 = Release|Any CPU + {3B29B35F-65E7-4819-9AED-EAC7FCFA309B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B29B35F-65E7-4819-9AED-EAC7FCFA309B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B29B35F-65E7-4819-9AED-EAC7FCFA309B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B29B35F-65E7-4819-9AED-EAC7FCFA309B}.Release|Any CPU.Build.0 = Release|Any CPU + {E4F50CA9-19A6-465A-9469-C033748AD95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4F50CA9-19A6-465A-9469-C033748AD95B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4F50CA9-19A6-465A-9469-C033748AD95B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4F50CA9-19A6-465A-9469-C033748AD95B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE