migrate database providers to core framework
This commit is contained in:
@ -10,10 +10,10 @@ namespace Oqtane.Controllers
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class DatabaseController : Controller
|
||||
{
|
||||
private IOptions<List<Database>> _databaseOptions;
|
||||
private IOptions<List<Models.Database>> _databaseOptions;
|
||||
private IConfigManager _config;
|
||||
|
||||
public DatabaseController(IOptions<List<Database>> databaseOptions, IConfigManager config)
|
||||
public DatabaseController(IOptions<List<Models.Database>> databaseOptions, IConfigManager config)
|
||||
{
|
||||
_databaseOptions = databaseOptions;
|
||||
_config = config;
|
||||
@ -21,7 +21,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
public IEnumerable<Database> Get()
|
||||
public IEnumerable<Models.Database> Get()
|
||||
{
|
||||
var databases = _databaseOptions.Value;
|
||||
var master = _config.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "");
|
||||
|
114
Oqtane.Server/Databases/MySQL/MySQLDatabase.cs
Normal file
114
Oqtane.Server/Databases/MySQL/MySQLDatabase.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Oqtane.Databases;
|
||||
|
||||
namespace Oqtane.Database.MySQL
|
||||
{
|
||||
public class MySQLDatabase : DatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "MySQL";
|
||||
|
||||
private static string _name => "MySQL";
|
||||
|
||||
static MySQLDatabase()
|
||||
{
|
||||
Initialize(typeof(MySQLDatabase));
|
||||
}
|
||||
|
||||
public MySQLDatabase() :base(_name, _friendlyName) { }
|
||||
|
||||
public override string Provider => "Pomelo.EntityFrameworkCore.MySql";
|
||||
|
||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||
{
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
|
||||
}
|
||||
|
||||
public override string ConcatenateSql(params string[] values)
|
||||
{
|
||||
var returnValue = "CONCAT(";
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
returnValue += ",";
|
||||
}
|
||||
returnValue += values[i];
|
||||
}
|
||||
|
||||
returnValue += ")";
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public override int ExecuteNonQuery(string connectionString, string query)
|
||||
{
|
||||
var conn = new MySqlConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
using (conn)
|
||||
{
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var val = -1;
|
||||
try
|
||||
{
|
||||
val = cmd.ExecuteNonQuery();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// an error occurred executing the query
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override IDataReader ExecuteReader(string connectionString, string query)
|
||||
{
|
||||
var conn = new MySqlConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
return dr;
|
||||
}
|
||||
|
||||
public override string DelimitName(string name)
|
||||
{
|
||||
return $"`{name}`";
|
||||
}
|
||||
|
||||
public override string RewriteValue(object value)
|
||||
{
|
||||
var type = value.GetType().Name;
|
||||
if (type == "DateTime")
|
||||
{
|
||||
return $"'{value}'";
|
||||
}
|
||||
if (type == "Boolean")
|
||||
{
|
||||
return (bool)value ? "1" : "0"; // MySQL uses 1/0 for boolean values
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
return optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
|
||||
}
|
||||
|
||||
private void PrepareCommand(MySqlConnection conn, MySqlCommand cmd, string query)
|
||||
{
|
||||
if (conn.State != ConnectionState.Open)
|
||||
{
|
||||
conn.Open();
|
||||
}
|
||||
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = query;
|
||||
cmd.CommandType = CommandType.Text;
|
||||
}
|
||||
}
|
||||
}
|
49
Oqtane.Server/Databases/PostgreSQL/HistoryRepository.cs
Normal file
49
Oqtane.Server/Databases/PostgreSQL/HistoryRepository.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal;
|
||||
using Oqtane.Migrations.Framework;
|
||||
using Oqtane.Models;
|
||||
|
||||
// ReSharper disable ClassNeverInstantiated.Global
|
||||
|
||||
namespace Oqtane.Database.PostgreSQL
|
||||
{
|
||||
public class HistoryRepository : NpgsqlHistoryRepository
|
||||
{
|
||||
private string _appliedDateColumnName = "applied_date";
|
||||
private string _appliedVersionColumnName = "applied_version";
|
||||
private MigrationHistoryTable _migrationHistoryTable;
|
||||
|
||||
public HistoryRepository(HistoryRepositoryDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_migrationHistoryTable = new MigrationHistoryTable
|
||||
{
|
||||
TableName = TableName,
|
||||
TableSchema = TableSchema,
|
||||
MigrationIdColumnName = MigrationIdColumnName,
|
||||
ProductVersionColumnName = ProductVersionColumnName,
|
||||
AppliedVersionColumnName = _appliedVersionColumnName,
|
||||
AppliedDateColumnName = _appliedDateColumnName
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
|
||||
{
|
||||
base.ConfigureTable(history);
|
||||
history.Property<string>(_appliedVersionColumnName).HasMaxLength(10);
|
||||
history.Property<DateTime>(_appliedDateColumnName);
|
||||
}
|
||||
|
||||
public override string GetInsertScript(HistoryRow row)
|
||||
{
|
||||
if (row == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(row));
|
||||
}
|
||||
|
||||
return MigrationUtils.BuildInsertScript(row, Dependencies, _migrationHistoryTable);
|
||||
}
|
||||
}
|
||||
}
|
165
Oqtane.Server/Databases/PostgreSQL/PostgreSQLDatabase.cs
Normal file
165
Oqtane.Server/Databases/PostgreSQL/PostgreSQLDatabase.cs
Normal file
@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using EFCore.NamingConventions.Internal;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Npgsql;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Oqtane.Databases;
|
||||
|
||||
namespace Oqtane.Database.PostgreSQL
|
||||
{
|
||||
public class PostgreSQLDatabase : DatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "PostgreSQL";
|
||||
|
||||
private static string _name => "PostgreSQL";
|
||||
|
||||
private readonly INameRewriter _rewriter;
|
||||
|
||||
static PostgreSQLDatabase()
|
||||
{
|
||||
Initialize(typeof(PostgreSQLDatabase));
|
||||
}
|
||||
|
||||
public PostgreSQLDatabase() : base(_name, _friendlyName)
|
||||
{
|
||||
_rewriter = new SnakeCaseNameRewriter(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public override string Provider => "Npgsql.EntityFrameworkCore.PostgreSQL";
|
||||
|
||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||
{
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
|
||||
}
|
||||
|
||||
public override string ConcatenateSql(params string[] values)
|
||||
{
|
||||
var returnValue = String.Empty;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
returnValue += " || ";
|
||||
}
|
||||
returnValue += values[i];
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public override int ExecuteNonQuery(string connectionString, string query)
|
||||
{
|
||||
var conn = new NpgsqlConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
using (conn)
|
||||
{
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var val = -1;
|
||||
try
|
||||
{
|
||||
val = cmd.ExecuteNonQuery();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// an error occurred executing the query
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override IDataReader ExecuteReader(string connectionString, string query)
|
||||
{
|
||||
var conn = new NpgsqlConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
return dr;
|
||||
}
|
||||
|
||||
public override string RewriteName(string name)
|
||||
{
|
||||
return _rewriter.RewriteName(name);
|
||||
}
|
||||
|
||||
public override string DelimitName(string name)
|
||||
{
|
||||
return $"\"{name}\"";
|
||||
}
|
||||
|
||||
public override string RewriteValue(object value)
|
||||
{
|
||||
var type = value.GetType().Name;
|
||||
if (type == "DateTime")
|
||||
{
|
||||
return $"'{value}'";
|
||||
}
|
||||
if (type == "Boolean")
|
||||
{
|
||||
return (bool)value ? "true" : "false"; // PostgreSQL uses true/false for boolean values
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public override void UpdateIdentityStoreTableNames(ModelBuilder builder)
|
||||
{
|
||||
foreach(var entity in builder.Model.GetEntityTypes())
|
||||
{
|
||||
var tableName = entity.GetTableName();
|
||||
if (tableName.StartsWith("AspNetUser"))
|
||||
{
|
||||
// replace table name
|
||||
entity.SetTableName(RewriteName(entity.GetTableName()));
|
||||
|
||||
// replace column names
|
||||
foreach(var property in entity.GetProperties())
|
||||
{
|
||||
property.SetColumnName(RewriteName(property.Name));
|
||||
}
|
||||
|
||||
// replace key names
|
||||
foreach(var key in entity.GetKeys())
|
||||
{
|
||||
key.SetName(RewriteName(key.GetName()));
|
||||
}
|
||||
|
||||
// replace foreign key names
|
||||
foreach (var key in entity.GetForeignKeys())
|
||||
{
|
||||
key.PrincipalKey.SetName(RewriteName(key.PrincipalKey.GetName()));
|
||||
}
|
||||
|
||||
// replace index names
|
||||
foreach (var index in entity.GetIndexes())
|
||||
{
|
||||
index.SetDatabaseName(RewriteName(index.GetDatabaseName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
return optionsBuilder.UseNpgsql(connectionString)
|
||||
.UseSnakeCaseNamingConvention()
|
||||
.ReplaceService<IHistoryRepository, HistoryRepository>();
|
||||
}
|
||||
|
||||
private void PrepareCommand(NpgsqlConnection conn, NpgsqlCommand cmd, string query)
|
||||
{
|
||||
if (conn.State != ConnectionState.Open)
|
||||
{
|
||||
conn.Open();
|
||||
}
|
||||
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = query;
|
||||
cmd.CommandType = CommandType.Text;
|
||||
}
|
||||
}
|
||||
}
|
49
Oqtane.Server/Databases/SqlServer/HistoryRepository.cs
Normal file
49
Oqtane.Server/Databases/SqlServer/HistoryRepository.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.SqlServer.Migrations.Internal;
|
||||
using Oqtane.Migrations.Framework;
|
||||
using Oqtane.Models;
|
||||
|
||||
// ReSharper disable ClassNeverInstantiated.Global
|
||||
|
||||
namespace Oqtane.Database.SqlServer
|
||||
{
|
||||
public class HistoryRepository : SqlServerHistoryRepository
|
||||
{
|
||||
private string _appliedDateColumnName = "AppliedDate";
|
||||
private string _appliedVersionColumnName = "AppliedVersion";
|
||||
private MigrationHistoryTable _migrationHistoryTable;
|
||||
|
||||
public HistoryRepository(HistoryRepositoryDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_migrationHistoryTable = new MigrationHistoryTable
|
||||
{
|
||||
TableName = TableName,
|
||||
TableSchema = TableSchema,
|
||||
MigrationIdColumnName = MigrationIdColumnName,
|
||||
ProductVersionColumnName = ProductVersionColumnName,
|
||||
AppliedVersionColumnName = _appliedVersionColumnName,
|
||||
AppliedDateColumnName = _appliedDateColumnName
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
|
||||
{
|
||||
base.ConfigureTable(history);
|
||||
history.Property<string>(_appliedVersionColumnName).HasMaxLength(10);
|
||||
history.Property<DateTime>(_appliedDateColumnName);
|
||||
}
|
||||
|
||||
public override string GetInsertScript(HistoryRow row)
|
||||
{
|
||||
if (row == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(row));
|
||||
}
|
||||
|
||||
return MigrationUtils.BuildInsertScript(row, Dependencies, _migrationHistoryTable);
|
||||
}
|
||||
}
|
||||
}
|
120
Oqtane.Server/Databases/SqlServer/SqlServerDatabase.cs
Normal file
120
Oqtane.Server/Databases/SqlServer/SqlServerDatabase.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases;
|
||||
|
||||
namespace Oqtane.Database.SqlServer
|
||||
{
|
||||
public class SqlServerDatabase : DatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "SQL Server";
|
||||
|
||||
private static string _name => "SqlServer";
|
||||
|
||||
static SqlServerDatabase()
|
||||
{
|
||||
Initialize(typeof(SqlServerDatabase));
|
||||
}
|
||||
|
||||
public SqlServerDatabase() : base(_name, _friendlyName)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Provider => "Microsoft.EntityFrameworkCore.SqlServer";
|
||||
|
||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||
{
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("SqlServer:Identity", "1, 1");
|
||||
}
|
||||
|
||||
public override void AlterStringColumn(MigrationBuilder builder, string name, string table, int length, bool nullable, bool unicode, string index)
|
||||
{
|
||||
var elements = index.Split(':', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (elements.Length != 0)
|
||||
{
|
||||
builder.DropIndex(elements[0], table);
|
||||
}
|
||||
builder.AlterColumn<string>(name, table, maxLength: length, nullable: nullable, unicode: unicode);
|
||||
if (elements.Length != 0)
|
||||
{
|
||||
var columns = elements[1].Split(',');
|
||||
builder.CreateIndex(elements[0], table, columns, null, bool.Parse(elements[2]), null);
|
||||
}
|
||||
}
|
||||
|
||||
public override string DelimitName(string name)
|
||||
{
|
||||
return $"[{name}]";
|
||||
}
|
||||
|
||||
public override string RewriteValue(object value)
|
||||
{
|
||||
var type = value.GetType().Name;
|
||||
if (type == "DateTime")
|
||||
{
|
||||
return $"'{value}'";
|
||||
}
|
||||
if (type == "Boolean")
|
||||
{
|
||||
return (bool)value ? "1" : "0"; // SQL Server uses 1/0 for boolean values
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public override int ExecuteNonQuery(string connectionString, string query)
|
||||
{
|
||||
var conn = new SqlConnection(FormatConnectionString(connectionString));
|
||||
var cmd = conn.CreateCommand();
|
||||
using (conn)
|
||||
{
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var val = -1;
|
||||
try
|
||||
{
|
||||
val = cmd.ExecuteNonQuery();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// an error occurred executing the query
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override IDataReader ExecuteReader(string connectionString, string query)
|
||||
{
|
||||
var conn = new SqlConnection(FormatConnectionString(connectionString));
|
||||
var cmd = conn.CreateCommand();
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
return dr;
|
||||
}
|
||||
|
||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
return optionsBuilder.UseSqlServer(connectionString)
|
||||
.ReplaceService<IHistoryRepository, HistoryRepository>();
|
||||
}
|
||||
|
||||
private string FormatConnectionString(string connectionString)
|
||||
{
|
||||
return connectionString.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString());
|
||||
}
|
||||
|
||||
private void PrepareCommand(SqlConnection conn, SqlCommand cmd, string query)
|
||||
{
|
||||
if (conn.State != ConnectionState.Open)
|
||||
{
|
||||
conn.Open();
|
||||
}
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = query;
|
||||
cmd.CommandType = CommandType.Text;
|
||||
}
|
||||
}
|
||||
}
|
49
Oqtane.Server/Databases/Sqlite/HistoryRepository.cs
Normal file
49
Oqtane.Server/Databases/Sqlite/HistoryRepository.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Sqlite.Migrations.Internal;
|
||||
using Oqtane.Migrations.Framework;
|
||||
using Oqtane.Models;
|
||||
|
||||
// ReSharper disable ClassNeverInstantiated.Global
|
||||
|
||||
namespace Oqtane.Database.Sqlite
|
||||
{
|
||||
public class HistoryRepository : SqliteHistoryRepository
|
||||
{
|
||||
private string _appliedDateColumnName = "AppliedDate";
|
||||
private string _appliedVersionColumnName = "AppliedVersion";
|
||||
private MigrationHistoryTable _migrationHistoryTable;
|
||||
|
||||
public HistoryRepository(HistoryRepositoryDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_migrationHistoryTable = new MigrationHistoryTable
|
||||
{
|
||||
TableName = TableName,
|
||||
TableSchema = TableSchema,
|
||||
MigrationIdColumnName = MigrationIdColumnName,
|
||||
ProductVersionColumnName = ProductVersionColumnName,
|
||||
AppliedVersionColumnName = _appliedVersionColumnName,
|
||||
AppliedDateColumnName = _appliedDateColumnName
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
|
||||
{
|
||||
base.ConfigureTable(history);
|
||||
history.Property<string>(_appliedVersionColumnName).HasMaxLength(10);
|
||||
history.Property<DateTime>(_appliedDateColumnName);
|
||||
}
|
||||
|
||||
public override string GetInsertScript(HistoryRow row)
|
||||
{
|
||||
if (row == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(row));
|
||||
}
|
||||
|
||||
return MigrationUtils.BuildInsertScript(row, Dependencies, _migrationHistoryTable);
|
||||
}
|
||||
}
|
||||
}
|
123
Oqtane.Server/Databases/Sqlite/SqliteDatabase.cs
Normal file
123
Oqtane.Server/Databases/Sqlite/SqliteDatabase.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases;
|
||||
|
||||
namespace Oqtane.Database.Sqlite
|
||||
{
|
||||
public class SqliteDatabase : DatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "SQLite";
|
||||
|
||||
private static string _name => "Sqlite";
|
||||
|
||||
static SqliteDatabase()
|
||||
{
|
||||
Initialize(typeof(SqliteDatabase));
|
||||
}
|
||||
|
||||
public SqliteDatabase() :base(_name, _friendlyName) { }
|
||||
|
||||
public override string Provider => "Microsoft.EntityFrameworkCore.Sqlite";
|
||||
|
||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||
{
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("Sqlite:Autoincrement", true);
|
||||
}
|
||||
|
||||
public override void DropColumn(MigrationBuilder builder, string name, string table)
|
||||
{
|
||||
// not implemented as SQLite does not support dropping columns
|
||||
}
|
||||
|
||||
public override void AlterStringColumn(MigrationBuilder builder, string name, string table, int length, bool nullable, bool unicode, string index)
|
||||
{
|
||||
// not implemented as SQLite does not support altering columns
|
||||
}
|
||||
|
||||
public override string ConcatenateSql(params string[] values)
|
||||
{
|
||||
var returnValue = String.Empty;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
returnValue += " || ";
|
||||
}
|
||||
returnValue += values[i];
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public override int ExecuteNonQuery(string connectionString, string query)
|
||||
{
|
||||
var conn = new SqliteConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
using (conn)
|
||||
{
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var val = -1;
|
||||
try
|
||||
{
|
||||
val = cmd.ExecuteNonQuery();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// an error occurred executing the query
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override IDataReader ExecuteReader(string connectionString, string query)
|
||||
{
|
||||
var conn = new SqliteConnection(connectionString);
|
||||
var cmd = conn.CreateCommand();
|
||||
PrepareCommand(conn, cmd, query);
|
||||
var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
return dr;
|
||||
}
|
||||
|
||||
public override string DelimitName(string name)
|
||||
{
|
||||
return $"\"{name}\"";
|
||||
}
|
||||
|
||||
public override string RewriteValue(object value)
|
||||
{
|
||||
var type = value.GetType().Name;
|
||||
if (type == "DateTime")
|
||||
{
|
||||
return $"'{value}'";
|
||||
}
|
||||
if (type == "Boolean")
|
||||
{
|
||||
return (bool)value ? "1" : "0"; // SQLite uses 1/0 for boolean values
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
return optionsBuilder.UseSqlite(connectionString)
|
||||
.ReplaceService<IHistoryRepository, HistoryRepository>();
|
||||
}
|
||||
|
||||
private void PrepareCommand(SqliteConnection conn, SqliteCommand cmd, string query)
|
||||
{
|
||||
if (conn.State != ConnectionState.Open)
|
||||
{
|
||||
conn.Open();
|
||||
}
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = query;
|
||||
cmd.CommandType = CommandType.Text;
|
||||
}
|
||||
}
|
||||
}
|
@ -663,7 +663,7 @@ namespace Oqtane.Infrastructure
|
||||
var connectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey));
|
||||
var databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
||||
|
||||
Oqtane.Databases.Interfaces.IDatabase database = null;
|
||||
Databases.Interfaces.IDatabase database = null;
|
||||
if (!string.IsNullOrEmpty(databaseType))
|
||||
{
|
||||
var type = Type.GetType(databaseType);
|
||||
@ -744,32 +744,34 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (_configManager.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "") == "")
|
||||
var defaultDatabaseType = _configManager.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "");
|
||||
if (defaultDatabaseType == "" || defaultDatabaseType.Contains(", Oqtane.Database."))
|
||||
{
|
||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", Constants.DefaultDBType, true);
|
||||
// DefaultDBType migrated to Oqtane.Server in 6.1.5
|
||||
defaultDatabaseType = defaultDatabaseType.Substring(0, defaultDatabaseType.IndexOf(", ")) + ", Oqtane.Server";
|
||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", defaultDatabaseType, true);
|
||||
}
|
||||
|
||||
var updateAvailableDatabases = false;
|
||||
if (!_configManager.GetSection(SettingKeys.AvailableDatabasesSection).Exists())
|
||||
{
|
||||
string databases = "[";
|
||||
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },";
|
||||
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Database.MySQL\" },";
|
||||
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }";
|
||||
databases += "]";
|
||||
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, databases, true);
|
||||
updateAvailableDatabases = true;
|
||||
}
|
||||
var availabledatabases = _configManager.GetSection(SettingKeys.AvailableDatabasesSection).GetChildren();
|
||||
if (!availabledatabases.Any(item => item.GetSection("Name").Value == "Azure SQL"))
|
||||
else
|
||||
{
|
||||
// available databases migrated to Oqtane.Server in 6.1.5
|
||||
updateAvailableDatabases = !_configManager.GetSection(SettingKeys.AvailableDatabasesSection).GetChildren()
|
||||
.Any(item => item.GetSection("DBType").Value == "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server");
|
||||
}
|
||||
if (updateAvailableDatabases)
|
||||
{
|
||||
// Azure SQL added in 6.1.2
|
||||
string databases = "[";
|
||||
foreach (var database in availabledatabases)
|
||||
{
|
||||
databases += "{ " + $"\"Name\": \"{database["Name"]}\", \"ControlType\": \"{database["ControlType"]}\", \"DBTYpe\": \"{database["DBType"]}\"" + " },";
|
||||
}
|
||||
databases += "{ \"Name\": \"Azure SQL\", \"ControlType\": \"Oqtane.Installer.Controls.AzureSqlConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" }";
|
||||
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server\" },";
|
||||
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server\" },";
|
||||
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Server\" },";
|
||||
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Server\" },";
|
||||
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Server\" },";
|
||||
databases += "{ \"Name\": \"Azure SQL\", \"ControlType\": \"Oqtane.Installer.Controls.AzureSqlConfig, Oqtane.Client\", \"DBType\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server\" }";
|
||||
databases += "]";
|
||||
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, databases, true);
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ namespace Oqtane.Infrastructure
|
||||
case "6.1.1":
|
||||
Upgrade_6_1_1(tenant, scope);
|
||||
break;
|
||||
case "6.1.5":
|
||||
Upgrade_6_1_5(tenant, scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -537,6 +540,24 @@ namespace Oqtane.Infrastructure
|
||||
AddPagesToSites(scope, tenant, pageTemplates);
|
||||
}
|
||||
|
||||
private void Upgrade_6_1_5(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
// remove Database Providers which were moved to Oqtane.Server
|
||||
string[] assemblies = {
|
||||
"Oqtane.Database.MySQL.dll",
|
||||
"Oqtane.Database.MySQL.pdb",
|
||||
"Oqtane.Database.PostgreSQL.dll",
|
||||
"Oqtane.Database.PostgreSQL.pdb",
|
||||
"Oqtane.Database.Sqlite.dll",
|
||||
"Oqtane.Database.Sqlite.pdb",
|
||||
"Oqtane.Database.SqlServer.dll",
|
||||
"Oqtane.Database.SqlServer.pdb"
|
||||
};
|
||||
|
||||
RemoveAssemblies(tenant, assemblies, "6.1.5");
|
||||
}
|
||||
|
||||
|
||||
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
||||
{
|
||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
|
@ -0,0 +1,33 @@
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.06.01.05.01")]
|
||||
public class UpdateTenantDBType : MultiDatabaseMigration
|
||||
{
|
||||
public UpdateTenantDBType(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// database providers moved to oqtane.server
|
||||
var tenantEntityBuilder = new TenantEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
tenantEntityBuilder.UpdateData("DBType", "'Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server'", $"{DelimitName(RewriteName("DBType"))} = 'Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer'");
|
||||
tenantEntityBuilder.UpdateData("DBType", "'Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Server'", $"{DelimitName(RewriteName("DBType"))} = 'Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite'");
|
||||
tenantEntityBuilder.UpdateData("DBType", "'Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Server'", $"{DelimitName(RewriteName("DBType"))} = 'Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Database.MySQL'");
|
||||
tenantEntityBuilder.UpdateData("DBType", "'Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Server'", $"{DelimitName(RewriteName("DBType"))} = 'Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL'");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
<EmbeddedResource Include="Scripts\MigrateMaster.sql" />
|
||||
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.8" />
|
||||
@ -44,33 +45,51 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.8" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- MySQL Database Provider Dependencies -->
|
||||
<PackageReference Include="MySql.Data" Version="9.4.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0-preview.3.efcore.9.0.0" />
|
||||
<!-- PostgreSQL Database Provider Dependencies -->
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.8" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<!-- SQLite Database Provider Dependencies -->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.8" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.1" />
|
||||
<!-- SQL Server Database Provider Dependencies -->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Suppress EF Core internal warnings for Database Providers -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<NoWarn>1701;1702;EF1001;AD0001;NU1608</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<NoWarn>1701;1702;EF1001;AD0001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ModuleTemplateFiles Include="$(ProjectDir)wwwroot\Modules\Templates\**\*.*" />
|
||||
<ThemeTemplateFiles Include="$(ProjectDir)wwwroot\Themes\Templates\**\*.*" />
|
||||
<MySQLFiles Include="$(OutputPath)Oqtane.Database.MySQL.dll;$(OutputPath)Oqtane.Database.MySQL.pdb;$(OutputPath)Pomelo.EntityFrameworkCore.MySql.dll;$(OutputPath)MySql.Data.dll" />
|
||||
<PostgreSQLFiles Include="$(OutputPath)Oqtane.Database.PostgreSQL.dll;$(OutputPath)Oqtane.Database.PostgreSQL.pdb;$(OutputPath)EFCore.NamingConventions.dll;$(OutputPath)Npgsql.EntityFrameworkCore.PostgreSQL.dll;$(OutputPath)Npgsql.dll" />
|
||||
<SqliteFiles Include="$(OutputPath)Oqtane.Database.Sqlite.dll;$(OutputPath)Oqtane.Database.Sqlite.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.Sqlite.dll" />
|
||||
<SqlServerFiles Include="$(OutputPath)Oqtane.Database.SqlServer.dll;$(OutputPath)Oqtane.Database.SqlServer.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.SqlServer.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AddPayloadsFolder" AfterTargets="Publish">
|
||||
<Copy SourceFiles="@(ModuleTemplateFiles)" DestinationFiles="@(ModuleTemplateFiles->'$(PublishDir)wwwroot\Modules\Templates\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(ThemeTemplateFiles)" DestinationFiles="@(ThemeTemplateFiles->'$(PublishDir)wwwroot\Themes\Templates\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(MySQLFiles)" DestinationFiles="@(MySQLFiles->'$(PublishDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(PostgreSQLFiles)" DestinationFiles="@(PostgreSQLFiles->'$(PublishDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(SqliteFiles)" DestinationFiles="@(SqliteFiles->'$(PublishDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(SqlServerFiles)" DestinationFiles="@(SqlServerFiles->'$(PublishDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- extends watching group to include *.dll files and exclude the ones cause an infinite loop -->
|
||||
<Watch Include="**\*.dll" Exclude="**\Microsoft.EntityFrameworkCore.*.dll;**\Oqtane.Database.*.dll;" />
|
||||
|
@ -69,7 +69,7 @@ namespace Oqtane
|
||||
// register localization services
|
||||
services.AddLocalization(options => options.ResourcesPath = "Resources");
|
||||
|
||||
services.AddOptions<List<Database>>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection));
|
||||
services.AddOptions<List<Models.Database>>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection));
|
||||
|
||||
// register scoped core services
|
||||
services.AddScoped<IAuthorizationHandler, PermissionHandler>()
|
||||
|
Reference in New Issue
Block a user