Fixed DbContext usage on Provider

This commit is contained in:
JPVenson 2025-01-27 16:35:46 +00:00
parent aa811eb1e3
commit 9d1c4ea169
10 changed files with 35 additions and 18 deletions

View File

@ -575,7 +575,11 @@ namespace Emby.Server.Implementations
/// <returns>A task representing the service initialization operation.</returns> /// <returns>A task representing the service initialization operation.</returns>
public async Task InitializeServices() public async Task InitializeServices()
{ {
var jellyfinDb = await Resolve<IDbContextFactory<JellyfinDbContext>>().CreateDbContextAsync().ConfigureAwait(false); var factory = Resolve<IDbContextFactory<JellyfinDbContext>>();
var provider = Resolve<IJellyfinDatabaseProvider>();
provider.DbContextFactory = factory;
var jellyfinDb = await factory.CreateDbContextAsync().ConfigureAwait(false);
await using (jellyfinDb.ConfigureAwait(false)) await using (jellyfinDb.ConfigureAwait(false))
{ {
if ((await jellyfinDb.Database.GetPendingMigrationsAsync().ConfigureAwait(false)).Any()) if ((await jellyfinDb.Database.GetPendingMigrationsAsync().ConfigureAwait(false)).Any())

View File

@ -10,6 +10,11 @@ namespace Jellyfin.Server.Implementations;
/// </summary> /// </summary>
public interface IJellyfinDatabaseProvider : IAsyncDisposable public interface IJellyfinDatabaseProvider : IAsyncDisposable
{ {
/// <summary>
/// Gets or Sets the Database Factory when initialisaition is done.
/// </summary>
IDbContextFactory<JellyfinDbContext>? DbContextFactory { get; set; }
/// <summary> /// <summary>
/// Initialises jellyfins EFCore database access. /// Initialises jellyfins EFCore database access.
/// </summary> /// </summary>

View File

@ -45,7 +45,7 @@
<ProjectReference Include="..\..\Jellyfin.Data\Jellyfin.Data.csproj" /> <ProjectReference Include="..\..\Jellyfin.Data\Jellyfin.Data.csproj" />
<ProjectReference Include="..\..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> <ProjectReference Include="..\..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
<ProjectReference Include="..\..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> <ProjectReference Include="..\..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
<ProjectReference Include="..\..\Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj" /> <!-- <ProjectReference Include="..\..\Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj" /> -->
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -19,7 +19,7 @@ namespace Jellyfin.Server.Implementations.Migrations
return new JellyfinDbContext( return new JellyfinDbContext(
optionsBuilder.Options, optionsBuilder.Options,
NullLogger<JellyfinDbContext>.Instance, NullLogger<JellyfinDbContext>.Instance,
new SqliteDatabaseProvider(null!, null!, NullLogger<SqliteDatabaseProvider>.Instance)); new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance));
} }
} }
} }

View File

@ -10,6 +10,7 @@ namespace Jellyfin.Database.Providers.SqLite;
/// <summary> /// <summary>
/// Configures jellyfin to use an SqLite database. /// Configures jellyfin to use an SqLite database.
/// </summary> /// </summary>
[JellyfinDatabaseProviderKey("Jellyfin-SqLite")]
public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider
{ {
private readonly IApplicationPaths _applicationPaths; private readonly IApplicationPaths _applicationPaths;
@ -18,17 +19,16 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SqliteDatabaseProvider"/> class. /// Initializes a new instance of the <see cref="SqliteDatabaseProvider"/> class.
/// </summary> /// </summary>
/// <param name="dbContextFactory">The Db context to interact with the database.</param>
/// <param name="applicationPaths">Service to construct the fallback when the old data path configuration is used.</param> /// <param name="applicationPaths">Service to construct the fallback when the old data path configuration is used.</param>
/// <param name="logger">A logger.</param> /// <param name="logger">A logger.</param>
public SqliteDatabaseProvider(IDbContextFactory<JellyfinDbContext> dbContextFactory, IApplicationPaths applicationPaths, ILogger<SqliteDatabaseProvider> logger) public SqliteDatabaseProvider(IApplicationPaths applicationPaths, ILogger<SqliteDatabaseProvider> logger)
{ {
DbContextFactory = dbContextFactory;
_applicationPaths = applicationPaths; _applicationPaths = applicationPaths;
_logger = logger; _logger = logger;
} }
private IDbContextFactory<JellyfinDbContext> DbContextFactory { get; } /// <inheritdoc/>
public IDbContextFactory<JellyfinDbContext>? DbContextFactory { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public void Initialise(DbContextOptionsBuilder options) public void Initialise(DbContextOptionsBuilder options)
@ -41,7 +41,7 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider
/// <inheritdoc/> /// <inheritdoc/>
public async Task RunScheduledOptimisation(CancellationToken cancellationToken) public async Task RunScheduledOptimisation(CancellationToken cancellationToken)
{ {
var context = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); var context = await DbContextFactory!.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
await using (context.ConfigureAwait(false)) await using (context.ConfigureAwait(false))
{ {
if (context.Database.IsSqlite()) if (context.Database.IsSqlite())
@ -67,7 +67,7 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
// Run before disposing the application // Run before disposing the application
var context = await DbContextFactory.CreateDbContextAsync().ConfigureAwait(false); var context = await DbContextFactory!.CreateDbContextAsync().ConfigureAwait(false);
await using (context.ConfigureAwait(false)) await using (context.ConfigureAwait(false))
{ {
await context.Database.ExecuteSqlRawAsync("PRAGMA optimize").ConfigureAwait(false); await context.Database.ExecuteSqlRawAsync("PRAGMA optimize").ConfigureAwait(false);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Jellyfin.Database.Providers.SqLite;
using Jellyfin.Server.Implementations.DatabaseConfiguration; using Jellyfin.Server.Implementations.DatabaseConfiguration;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -17,14 +18,15 @@ namespace Jellyfin.Server.Implementations.Extensions;
/// </summary> /// </summary>
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
private static IEnumerable<Type> DatabaseProviderTypes()
{
yield return typeof(SqliteDatabaseProvider);
}
private static IDictionary<string, JellyfinDbProviderFactory> GetSupportedDbProviders() private static IDictionary<string, JellyfinDbProviderFactory> GetSupportedDbProviders()
{ {
var items = new Dictionary<string, JellyfinDbProviderFactory>(); var items = new Dictionary<string, JellyfinDbProviderFactory>();
foreach (var providerType in AppDomain foreach (var providerType in DatabaseProviderTypes())
.CurrentDomain
.GetAssemblies()
.SelectMany(f => f.GetTypes())
.Where(e => e.IsClass && typeof(IJellyfinDatabaseProvider).IsAssignableFrom(e)))
{ {
var keyAttribute = providerType.GetCustomAttribute<JellyfinDatabaseProviderKeyAttribute>(); var keyAttribute = providerType.GetCustomAttribute<JellyfinDatabaseProviderKeyAttribute>();
if (keyAttribute is null || string.IsNullOrWhiteSpace(keyAttribute.DatabaseProviderKey)) if (keyAttribute is null || string.IsNullOrWhiteSpace(keyAttribute.DatabaseProviderKey))
@ -51,15 +53,16 @@ public static class ServiceCollectionExtensions
var providers = GetSupportedDbProviders(); var providers = GetSupportedDbProviders();
JellyfinDbProviderFactory? providerFactory = null; JellyfinDbProviderFactory? providerFactory = null;
if (efCoreConfiguration is null) if (efCoreConfiguration?.DatabaseType is null)
{ {
// when nothing is setup via new Database configuration, fallback to SqLite with default settings. // when nothing is setup via new Database configuration, fallback to SqLite with default settings.
efCoreConfiguration = new DatabaseConfigurationOptions() efCoreConfiguration = new DatabaseConfigurationOptions()
{ {
DatabaseType = "SqLite", DatabaseType = "Jellyfin-SqLite",
}; };
} }
else if (!providers.TryGetValue(efCoreConfiguration.DatabaseType, out providerFactory!))
if (!providers.TryGetValue(efCoreConfiguration.DatabaseType, out providerFactory!))
{ {
throw new InvalidOperationException($"Jellyfin cannot find the database provider of type '{efCoreConfiguration.DatabaseType}'. Supported types are {string.Join(", ", providers.Keys)}"); throw new InvalidOperationException($"Jellyfin cannot find the database provider of type '{efCoreConfiguration.DatabaseType}'. Supported types are {string.Join(", ", providers.Keys)}");
} }

View File

@ -36,6 +36,7 @@
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
<ProjectReference Include="..\Jellyfin.Database\Jellyfin.Database.Implementations\Jellyfin.Database.Implementations.csproj" /> <ProjectReference Include="..\Jellyfin.Database\Jellyfin.Database.Implementations\Jellyfin.Database.Implementations.csproj" />
<ProjectReference Include="..\Jellyfin.Database\Jellyfin.Database.Providers.SqLite\Jellyfin.Database.Providers.SqLite.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,6 +11,7 @@ using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Activity;
using Jellyfin.Server.Implementations.Devices; using Jellyfin.Server.Implementations.Devices;
using Jellyfin.Server.Implementations.Events; using Jellyfin.Server.Implementations.Events;
using Jellyfin.Server.Implementations.Extensions;
using Jellyfin.Server.Implementations.Security; using Jellyfin.Server.Implementations.Security;
using Jellyfin.Server.Implementations.Trickplay; using Jellyfin.Server.Implementations.Trickplay;
using Jellyfin.Server.Implementations.Users; using Jellyfin.Server.Implementations.Users;
@ -116,9 +117,12 @@ namespace Jellyfin.Server
// Jellyfin.Server // Jellyfin.Server
yield return typeof(CoreAppHost).Assembly; yield return typeof(CoreAppHost).Assembly;
// Jellyfin.Server.Implementations // Jellyfin.Database.Implementations
yield return typeof(JellyfinDbContext).Assembly; yield return typeof(JellyfinDbContext).Assembly;
// Jellyfin.Server.Implementations
yield return typeof(ServiceCollectionExtensions).Assembly;
// Jellyfin.LiveTv // Jellyfin.LiveTv
yield return typeof(LiveTvManager).Assembly; yield return typeof(LiveTvManager).Assembly;
} }