feat: Let the DbContext handle the connection to the database (#14674)
This commit is contained in:
committed by
GitHub
parent
7b336c45f7
commit
3f6ebe7656
@@ -17,8 +17,6 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
public static IServiceCollection AddUmbracoEFCoreContext<T>(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
|
||||
where T : DbContext
|
||||
{
|
||||
defaultEFCoreOptionsAction ??= DefaultOptionsAction;
|
||||
|
||||
services.AddPooledDbContextFactory<T>((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder));
|
||||
services.AddTransient(services => services.GetRequiredService<IDbContextFactory<T>>().CreateDbContext());
|
||||
|
||||
@@ -31,38 +29,9 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void SetupDbContext(DefaultEFCoreOptionsAction defaultEFCoreOptionsAction, IServiceProvider provider, DbContextOptionsBuilder builder)
|
||||
{
|
||||
ConnectionStrings connectionStrings = GetConnectionStringAndProviderName(provider);
|
||||
IEnumerable<IMigrationProviderSetup> migrationProviders = provider.GetServices<IMigrationProviderSetup>();
|
||||
IMigrationProviderSetup? migrationProvider =
|
||||
migrationProviders.FirstOrDefault(x => x.ProviderName == connectionStrings.ProviderName);
|
||||
migrationProvider?.Setup(builder, connectionStrings.ConnectionString);
|
||||
defaultEFCoreOptionsAction(builder, connectionStrings.ConnectionString, connectionStrings.ProviderName);
|
||||
}
|
||||
|
||||
private static ConnectionStrings GetConnectionStringAndProviderName(IServiceProvider serviceProvider)
|
||||
{
|
||||
string? connectionString = null;
|
||||
string? providerName = null;
|
||||
|
||||
ConnectionStrings connectionStrings = serviceProvider.GetRequiredService<IOptionsMonitor<ConnectionStrings>>().CurrentValue;
|
||||
|
||||
// Replace data directory
|
||||
string? dataDirectory = AppDomain.CurrentDomain.GetData(Constants.System.DataDirectoryName)?.ToString();
|
||||
if (string.IsNullOrEmpty(dataDirectory) is false)
|
||||
{
|
||||
connectionStrings.ConnectionString = connectionStrings.ConnectionString?.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
|
||||
return connectionStrings;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddUmbracoEFCoreContext<T>(this IServiceCollection services, string connectionString, string providerName, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
|
||||
where T : DbContext
|
||||
{
|
||||
defaultEFCoreOptionsAction ??= DefaultOptionsAction;
|
||||
|
||||
// Replace data directory
|
||||
string? dataDirectory = AppDomain.CurrentDomain.GetData(Constants.System.DataDirectoryName)?.ToString();
|
||||
if (string.IsNullOrEmpty(dataDirectory) is false)
|
||||
@@ -70,7 +39,7 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
connectionString = connectionString.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
|
||||
services.AddPooledDbContextFactory<T>((_, options) => defaultEFCoreOptionsAction(options, providerName, connectionString));
|
||||
services.AddPooledDbContextFactory<T>(options => defaultEFCoreOptionsAction?.Invoke(options, providerName, connectionString));
|
||||
services.AddTransient(services => services.GetRequiredService<IDbContextFactory<T>>().CreateDbContext());
|
||||
|
||||
services.AddUnique<IAmbientEFCoreScopeStack<T>, AmbientEFCoreScopeStack<T>>();
|
||||
@@ -82,21 +51,23 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void DefaultOptionsAction(DbContextOptionsBuilder options, string? providerName, string? connectionString)
|
||||
private static void SetupDbContext(DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction, IServiceProvider provider, DbContextOptionsBuilder builder)
|
||||
{
|
||||
if (connectionString.IsNullOrWhiteSpace())
|
||||
ConnectionStrings connectionStrings = GetConnectionStringAndProviderName(provider);
|
||||
defaultEFCoreOptionsAction?.Invoke(builder, connectionStrings.ConnectionString, connectionStrings.ProviderName);
|
||||
}
|
||||
|
||||
private static ConnectionStrings GetConnectionStringAndProviderName(IServiceProvider serviceProvider)
|
||||
{
|
||||
ConnectionStrings connectionStrings = serviceProvider.GetRequiredService<IOptionsMonitor<ConnectionStrings>>().CurrentValue;
|
||||
|
||||
// Replace data directory
|
||||
string? dataDirectory = AppDomain.CurrentDomain.GetData(Constants.System.DataDirectoryName)?.ToString();
|
||||
if (string.IsNullOrEmpty(dataDirectory) is false)
|
||||
{
|
||||
return;
|
||||
connectionStrings.ConnectionString = connectionStrings.ConnectionString?.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
|
||||
switch (providerName)
|
||||
{
|
||||
case "Microsoft.Data.Sqlite":
|
||||
options.UseSqlite(connectionString);
|
||||
break;
|
||||
case "Microsoft.Data.SqlClient":
|
||||
options.UseSqlServer(connectionString);
|
||||
break;
|
||||
}
|
||||
return connectionStrings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Persistence.EFCore.Migrations;
|
||||
|
||||
namespace Umbraco.Cms.Persistence.EFCore;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the Umbraco EF Core database context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To autogenerate migrations use the following commands
|
||||
/// and insure the 'src/Umbraco.Web.UI/appsettings.json' have a connection string set with the right provider.
|
||||
@@ -23,9 +32,44 @@ namespace Umbraco.Cms.Persistence.EFCore;
|
||||
/// </remarks>
|
||||
public class UmbracoDbContext : DbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoDbContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public UmbracoDbContext(DbContextOptions<UmbracoDbContext> options)
|
||||
: base(options)
|
||||
: base(ConfigureOptions(options, out IOptionsMonitor<ConnectionStrings>? connectionStringsOptionsMonitor))
|
||||
{
|
||||
connectionStringsOptionsMonitor.OnChange(c =>
|
||||
{
|
||||
ILogger<UmbracoDbContext> logger = StaticServiceProvider.Instance.GetRequiredService<ILogger<UmbracoDbContext>>();
|
||||
logger.LogWarning("Connection string changed, disposing context");
|
||||
Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
private static DbContextOptions<UmbracoDbContext> ConfigureOptions(DbContextOptions<UmbracoDbContext> options, out IOptionsMonitor<ConnectionStrings> connectionStringsOptionsMonitor)
|
||||
{
|
||||
connectionStringsOptionsMonitor = StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<ConnectionStrings>>();
|
||||
|
||||
ConnectionStrings connectionStrings = connectionStringsOptionsMonitor.CurrentValue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(connectionStrings.ConnectionString))
|
||||
{
|
||||
ILogger<UmbracoDbContext> logger = StaticServiceProvider.Instance.GetRequiredService<ILogger<UmbracoDbContext>>();
|
||||
logger.LogCritical("No connection string was found, cannot setup Umbraco EF Core context");
|
||||
}
|
||||
|
||||
IEnumerable<IMigrationProviderSetup> migrationProviders = StaticServiceProvider.Instance.GetServices<IMigrationProviderSetup>();
|
||||
IMigrationProviderSetup? migrationProvider = migrationProviders.FirstOrDefault(x => x.ProviderName == connectionStrings.ProviderName);
|
||||
|
||||
if (migrationProvider == null && connectionStrings.ProviderName != null)
|
||||
{
|
||||
throw new InvalidOperationException($"No migration provider found for provider name {connectionStrings.ProviderName}");
|
||||
}
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<UmbracoDbContext>(options);
|
||||
migrationProvider?.Setup(optionsBuilder, connectionStrings.ConnectionString);
|
||||
return optionsBuilder.Options;
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
||||
Reference in New Issue
Block a user