btcpayserver/BTCPayServer.Abstractions/Contracts/BaseDbContextFactory.cs

95 lines
4.1 KiB
C#
Raw Normal View History

using System;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Options;
using Npgsql;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
namespace BTCPayServer.Abstractions.Contracts
{
2021-12-31 16:59:02 +09:00
public abstract class BaseDbContextFactory<T> where T : DbContext
{
private readonly IOptions<DatabaseOptions> _options;
2024-04-15 19:08:25 +09:00
private readonly string _migrationTableName;
2024-04-15 19:08:25 +09:00
public BaseDbContextFactory(IOptions<DatabaseOptions> options, string migrationTableName)
{
_options = options;
2024-04-15 19:08:25 +09:00
_migrationTableName = migrationTableName;
}
public T CreateContext() => CreateContext(null);
public abstract T CreateContext(Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null);
class CustomNpgsqlMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
{
2021-12-27 13:46:31 +09:00
#pragma warning disable EF1001 // Internal EF Core API usage.
2022-07-27 15:55:37 +09:00
public CustomNpgsqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.INpgsqlSingletonOptions opts) : base(dependencies, opts)
2021-12-27 13:46:31 +09:00
#pragma warning restore EF1001 // Internal EF Core API usage.
{
}
protected override void Generate(NpgsqlCreateDatabaseOperation operation, IModel model, MigrationCommandListBuilder builder)
{
builder
.Append("CREATE DATABASE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name));
// POSTGRES gotcha: Indexed Text column (even if PK) are not used if we are not using C locale
builder
.Append(" TEMPLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("template0"));
builder
.Append(" LC_CTYPE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" LC_COLLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" ENCODING ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("UTF8"));
if (operation.Tablespace != null)
{
builder
.Append(" TABLESPACE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Tablespace));
}
builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
EndStatement(builder, suppressTransaction: true);
}
}
public void ConfigureBuilder(DbContextOptionsBuilder builder) => ConfigureBuilder(builder, null);
public void ConfigureBuilder(DbContextOptionsBuilder builder, Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
{
2024-04-15 19:08:25 +09:00
builder
.UseNpgsql(_options.Value.ConnectionString, o =>
{
2024-04-15 19:08:25 +09:00
o.EnableRetryOnFailure(10);
o.SetPostgresVersion(12, 0);
npgsqlOptionsAction?.Invoke(o);
var mainSearchPath = GetSearchPath(_options.Value.ConnectionString);
var schemaPrefix = string.IsNullOrEmpty(_migrationTableName) ? "__EFMigrationsHistory" : _migrationTableName;
o.MigrationsHistoryTable(schemaPrefix, mainSearchPath);
2024-04-15 19:08:25 +09:00
})
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
}
2021-12-31 16:59:02 +09:00
private string GetSearchPath(string connectionString)
{
var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
var searchPaths = connectionStringBuilder.SearchPath?.Split(',');
return searchPaths is not { Length: > 0 } ? null : searchPaths[0];
}
}
}