Преглед изворни кода

Merge pull request #9108 from barronpm/efcore-cleanup

Bond-009 пре 2 година
родитељ
комит
875359d457
30 измењених фајлова са 256 додато и 250 уклоњено
  1. 1 1
      Emby.Server.Implementations/ApplicationHost.cs
  2. 2 2
      Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
  3. 16 16
      Jellyfin.Server.Implementations/Activity/ActivityManager.cs
  4. 9 21
      Jellyfin.Server.Implementations/Devices/DeviceManager.cs
  5. 2 5
      Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs
  6. 0 162
      Jellyfin.Server.Implementations/JellyfinDb.cs
  7. 188 0
      Jellyfin.Server.Implementations/JellyfinDbContext.cs
  8. 1 1
      Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs
  9. 1 1
      Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs
  10. 1 1
      Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs
  11. 1 1
      Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs
  12. 1 1
      Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs
  13. 1 1
      Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs
  14. 1 1
      Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs
  15. 1 1
      Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs
  16. 1 1
      Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs
  17. 1 1
      Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs
  18. 5 5
      Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs
  19. 1 1
      Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
  20. 2 4
      Jellyfin.Server.Implementations/Security/AuthenticationManager.cs
  21. 2 2
      Jellyfin.Server.Implementations/Security/AuthorizationContext.cs
  22. 2 5
      Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
  23. 5 5
      Jellyfin.Server.Implementations/Users/UserManager.cs
  24. 1 1
      Jellyfin.Server/CoreAppHost.cs
  25. 2 2
      Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
  26. 2 2
      Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs
  27. 2 2
      Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
  28. 2 2
      Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
  29. 1 1
      Jellyfin.Server/Program.cs
  30. 1 1
      Jellyfin.Server/Startup.cs

+ 1 - 1
Emby.Server.Implementations/ApplicationHost.cs

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

+ 2 - 2
Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs

@@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
     {
         private readonly ILogger<OptimizeDatabaseTask> _logger;
         private readonly ILocalizationManager _localization;
-        private readonly IDbContextFactory<JellyfinDb> _provider;
+        private readonly IDbContextFactory<JellyfinDbContext> _provider;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="OptimizeDatabaseTask" /> class.
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         public OptimizeDatabaseTask(
             ILogger<OptimizeDatabaseTask> logger,
             ILocalizationManager localization,
-            IDbContextFactory<JellyfinDb> provider)
+            IDbContextFactory<JellyfinDbContext> provider)
         {
             _logger = logger;
             _localization = localization;

+ 16 - 16
Jellyfin.Server.Implementations/Activity/ActivityManager.cs

@@ -15,13 +15,13 @@ namespace Jellyfin.Server.Implementations.Activity
     /// </summary>
     public class ActivityManager : IActivityManager
     {
-        private readonly IDbContextFactory<JellyfinDb> _provider;
+        private readonly IDbContextFactory<JellyfinDbContext> _provider;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ActivityManager"/> class.
         /// </summary>
         /// <param name="provider">The Jellyfin database provider.</param>
-        public ActivityManager(IDbContextFactory<JellyfinDb> provider)
+        public ActivityManager(IDbContextFactory<JellyfinDbContext> provider)
         {
             _provider = provider;
         }
@@ -48,18 +48,10 @@ namespace Jellyfin.Server.Implementations.Activity
             var dbContext = await _provider.CreateDbContextAsync().ConfigureAwait(false);
             await using (dbContext.ConfigureAwait(false))
             {
-                IQueryable<ActivityLog> entries = dbContext.ActivityLogs
-                    .OrderByDescending(entry => entry.DateCreated);
-
-                if (query.MinDate.HasValue)
-                {
-                    entries = entries.Where(entry => entry.DateCreated >= query.MinDate);
-                }
-
-                if (query.HasUserId.HasValue)
-                {
-                    entries = entries.Where(entry => (!entry.UserId.Equals(default)) == query.HasUserId.Value);
-                }
+                var entries = dbContext.ActivityLogs
+                    .OrderByDescending(entry => entry.DateCreated)
+                    .Where(entry => query.MinDate == null || entry.DateCreated >= query.MinDate)
+                    .Where(entry => !query.HasUserId.HasValue || entry.UserId.Equals(default) != query.HasUserId.Value);
 
                 return new QueryResult<ActivityLogEntry>(
                     query.Skip,
@@ -67,8 +59,16 @@ namespace Jellyfin.Server.Implementations.Activity
                     await entries
                         .Skip(query.Skip ?? 0)
                         .Take(query.Limit ?? 100)
-                        .AsAsyncEnumerable()
-                        .Select(ConvertToOldModel)
+                        .Select(entity => new ActivityLogEntry(entity.Name, entity.Type, entity.UserId)
+                        {
+                            Id = entity.Id,
+                            Overview = entity.Overview,
+                            ShortOverview = entity.ShortOverview,
+                            ItemId = entity.ItemId,
+                            Date = entity.DateCreated,
+                            Severity = entity.LogSeverity
+                        })
+                        .AsQueryable()
                         .ToListAsync()
                         .ConfigureAwait(false));
             }

+ 9 - 21
Jellyfin.Server.Implementations/Devices/DeviceManager.cs

@@ -23,7 +23,7 @@ namespace Jellyfin.Server.Implementations.Devices
     /// </summary>
     public class DeviceManager : IDeviceManager
     {
-        private readonly IDbContextFactory<JellyfinDb> _dbProvider;
+        private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
         private readonly IUserManager _userManager;
         private readonly ConcurrentDictionary<string, ClientCapabilities> _capabilitiesMap = new();
 
@@ -32,7 +32,7 @@ namespace Jellyfin.Server.Implementations.Devices
         /// </summary>
         /// <param name="dbProvider">The database provider.</param>
         /// <param name="userManager">The user manager.</param>
-        public DeviceManager(IDbContextFactory<JellyfinDb> dbProvider, IUserManager userManager)
+        public DeviceManager(IDbContextFactory<JellyfinDbContext> dbProvider, IUserManager userManager)
         {
             _dbProvider = dbProvider;
             _userManager = userManager;
@@ -54,7 +54,7 @@ namespace Jellyfin.Server.Implementations.Devices
             var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
             await using (dbContext.ConfigureAwait(false))
             {
-                deviceOptions = await dbContext.DeviceOptions.AsQueryable().FirstOrDefaultAsync(dev => dev.DeviceId == deviceId).ConfigureAwait(false);
+                deviceOptions = await dbContext.DeviceOptions.FirstOrDefaultAsync(dev => dev.DeviceId == deviceId).ConfigureAwait(false);
                 if (deviceOptions is null)
                 {
                     deviceOptions = new DeviceOptions(deviceId);
@@ -132,22 +132,11 @@ namespace Jellyfin.Server.Implementations.Devices
             var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
             await using (dbContext.ConfigureAwait(false))
             {
-                var devices = dbContext.Devices.AsQueryable();
-
-                if (query.UserId.HasValue)
-                {
-                    devices = devices.Where(device => device.UserId.Equals(query.UserId.Value));
-                }
-
-                if (query.DeviceId is not null)
-                {
-                    devices = devices.Where(device => device.DeviceId == query.DeviceId);
-                }
-
-                if (query.AccessToken is not null)
-                {
-                    devices = devices.Where(device => device.AccessToken == query.AccessToken);
-                }
+                var devices = dbContext.Devices
+                    .OrderBy(d => d.Id)
+                    .Where(device => !query.UserId.HasValue || device.UserId.Equals(query.UserId.Value))
+                    .Where(device => query.DeviceId == null || device.DeviceId == query.DeviceId)
+                    .Where(device => query.AccessToken == null || device.AccessToken == query.AccessToken);
 
                 var count = await devices.CountAsync().ConfigureAwait(false);
 
@@ -179,11 +168,10 @@ namespace Jellyfin.Server.Implementations.Devices
         /// <inheritdoc />
         public async Task<QueryResult<DeviceInfo>> GetDevicesForUser(Guid? userId, bool? supportsSync)
         {
-            IAsyncEnumerable<Device> sessions;
             var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
             await using (dbContext.ConfigureAwait(false))
             {
-                sessions = dbContext.Devices
+                IAsyncEnumerable<Device> sessions = dbContext.Devices
                     .Include(d => d.User)
                     .OrderByDescending(d => d.DateLastActivity)
                     .ThenBy(d => d.DeviceId)

+ 2 - 5
Jellyfin.Server.Implementations/Extensions/ServiceCollectionExtensions.cs

@@ -4,7 +4,6 @@ using EFCoreSecondLevelCacheInterceptor;
 using MediaBrowser.Common.Configuration;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
 
 namespace Jellyfin.Server.Implementations.Extensions;
 
@@ -29,13 +28,11 @@ public static class ServiceCollectionExtensions
                 .SkipCachingResults(result =>
                     result.Value is null || (result.Value is EFTableRows rows && rows.RowsCount == 0)));
 
-        serviceCollection.AddPooledDbContextFactory<JellyfinDb>((serviceProvider, opt) =>
+        serviceCollection.AddPooledDbContextFactory<JellyfinDbContext>((serviceProvider, opt) =>
         {
             var applicationPaths = serviceProvider.GetRequiredService<IApplicationPaths>();
-            var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
             opt.UseSqlite($"Filename={Path.Combine(applicationPaths.DataPath, "jellyfin.db")}")
-                .AddInterceptors(serviceProvider.GetRequiredService<SecondLevelCacheInterceptor>())
-                .UseLoggerFactory(loggerFactory);
+                .AddInterceptors(serviceProvider.GetRequiredService<SecondLevelCacheInterceptor>());
         });
 
         return serviceCollection;

+ 0 - 162
Jellyfin.Server.Implementations/JellyfinDb.cs

@@ -1,162 +0,0 @@
-#nullable disable
-#pragma warning disable CS1591
-
-using System;
-using System.Linq;
-using Jellyfin.Data.Entities;
-using Jellyfin.Data.Entities.Security;
-using Jellyfin.Data.Interfaces;
-using Microsoft.EntityFrameworkCore;
-
-namespace Jellyfin.Server.Implementations
-{
-    /// <inheritdoc/>
-    public class JellyfinDb : DbContext
-    {
-        /// <summary>
-        /// Initializes a new instance of the <see cref="JellyfinDb"/> class.
-        /// </summary>
-        /// <param name="options">The database context options.</param>
-        public JellyfinDb(DbContextOptions<JellyfinDb> options) : base(options)
-        {
-        }
-
-        /// <summary>
-        /// Gets or sets the default connection string.
-        /// </summary>
-        public static string ConnectionString { get; set; } = @"Data Source=jellyfin.db";
-
-        public virtual DbSet<AccessSchedule> AccessSchedules { get; set; }
-
-        public virtual DbSet<ActivityLog> ActivityLogs { get; set; }
-
-        public virtual DbSet<ApiKey> ApiKeys { get; set; }
-
-        public virtual DbSet<Device> Devices { get; set; }
-
-        public virtual DbSet<DeviceOptions> DeviceOptions { get; set; }
-
-        public virtual DbSet<DisplayPreferences> DisplayPreferences { get; set; }
-
-        public virtual DbSet<ImageInfo> ImageInfos { get; set; }
-
-        public virtual DbSet<ItemDisplayPreferences> ItemDisplayPreferences { get; set; }
-
-        public virtual DbSet<CustomItemDisplayPreferences> CustomItemDisplayPreferences { get; set; }
-
-        public virtual DbSet<Permission> Permissions { get; set; }
-
-        public virtual DbSet<Preference> Preferences { get; set; }
-
-        public virtual DbSet<User> Users { get; set; }
-
-        /*public virtual DbSet<Artwork> Artwork { get; set; }
-
-        public virtual DbSet<Book> Books { get; set; }
-
-        public virtual DbSet<BookMetadata> BookMetadata { get; set; }
-
-        public virtual DbSet<Chapter> Chapters { get; set; }
-
-        public virtual DbSet<Collection> Collections { get; set; }
-
-        public virtual DbSet<CollectionItem> CollectionItems { get; set; }
-
-        public virtual DbSet<Company> Companies { get; set; }
-
-        public virtual DbSet<CompanyMetadata> CompanyMetadata { get; set; }
-
-        public virtual DbSet<CustomItem> CustomItems { get; set; }
-
-        public virtual DbSet<CustomItemMetadata> CustomItemMetadata { get; set; }
-
-        public virtual DbSet<Episode> Episodes { get; set; }
-
-        public virtual DbSet<EpisodeMetadata> EpisodeMetadata { get; set; }
-
-        public virtual DbSet<Genre> Genres { get; set; }
-
-        public virtual DbSet<Group> Groups { get; set; }
-
-        public virtual DbSet<Library> Libraries { get; set; }
-
-        public virtual DbSet<LibraryItem> LibraryItems { get; set; }
-
-        public virtual DbSet<LibraryRoot> LibraryRoot { get; set; }
-
-        public virtual DbSet<MediaFile> MediaFiles { get; set; }
-
-        public virtual DbSet<MediaFileStream> MediaFileStream { get; set; }
-
-        public virtual DbSet<Metadata> Metadata { get; set; }
-
-        public virtual DbSet<MetadataProvider> MetadataProviders { get; set; }
-
-        public virtual DbSet<MetadataProviderId> MetadataProviderIds { get; set; }
-
-        public virtual DbSet<Movie> Movies { get; set; }
-
-        public virtual DbSet<MovieMetadata> MovieMetadata { get; set; }
-
-        public virtual DbSet<MusicAlbum> MusicAlbums { get; set; }
-
-        public virtual DbSet<MusicAlbumMetadata> MusicAlbumMetadata { get; set; }
-
-        public virtual DbSet<Person> People { get; set; }
-
-        public virtual DbSet<PersonRole> PersonRoles { get; set; }
-
-        public virtual DbSet<Photo> Photo { get; set; }
-
-        public virtual DbSet<PhotoMetadata> PhotoMetadata { get; set; }
-
-        public virtual DbSet<ProviderMapping> ProviderMappings { get; set; }
-
-        public virtual DbSet<Rating> Ratings { get; set; }
-
-        /// <summary>
-        /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to
-        /// store review ratings, not age ratings.
-        /// </summary>
-        public virtual DbSet<RatingSource> RatingSources { get; set; }
-
-        public virtual DbSet<Release> Releases { get; set; }
-
-        public virtual DbSet<Season> Seasons { get; set; }
-
-        public virtual DbSet<SeasonMetadata> SeasonMetadata { get; set; }
-
-        public virtual DbSet<Series> Series { get; set; }
-
-        public virtual DbSet<SeriesMetadata> SeriesMetadata { get; set; }
-
-        public virtual DbSet<Track> Tracks { get; set; }
-
-        public virtual DbSet<TrackMetadata> TrackMetadata { get; set; }*/
-
-        /// <inheritdoc/>
-        public override int SaveChanges()
-        {
-            foreach (var saveEntity in ChangeTracker.Entries()
-                .Where(e => e.State == EntityState.Modified)
-                .Select(entry => entry.Entity)
-                .OfType<IHasConcurrencyToken>())
-            {
-                saveEntity.OnSavingChanges();
-            }
-
-            return base.SaveChanges();
-        }
-
-        /// <inheritdoc />
-        protected override void OnModelCreating(ModelBuilder modelBuilder)
-        {
-            modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
-            base.OnModelCreating(modelBuilder);
-            modelBuilder.HasDefaultSchema("jellyfin");
-
-            // Configuration for each entity is in it's own class inside 'ModelConfiguration'.
-            modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDb).Assembly);
-        }
-    }
-}

+ 188 - 0
Jellyfin.Server.Implementations/JellyfinDbContext.cs

@@ -0,0 +1,188 @@
+using System;
+using System.Linq;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Entities.Security;
+using Jellyfin.Data.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace Jellyfin.Server.Implementations;
+
+/// <inheritdoc/>
+public class JellyfinDbContext : DbContext
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="JellyfinDbContext"/> class.
+    /// </summary>
+    /// <param name="options">The database context options.</param>
+    public JellyfinDbContext(DbContextOptions<JellyfinDbContext> options) : base(options)
+    {
+    }
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the access schedules.
+    /// </summary>
+    public DbSet<AccessSchedule> AccessSchedules => Set<AccessSchedule>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the activity logs.
+    /// </summary>
+    public DbSet<ActivityLog> ActivityLogs => Set<ActivityLog>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the API keys.
+    /// </summary>
+    public DbSet<ApiKey> ApiKeys => Set<ApiKey>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the devices.
+    /// </summary>
+    public DbSet<Device> Devices => Set<Device>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the device options.
+    /// </summary>
+    public DbSet<DeviceOptions> DeviceOptions => Set<DeviceOptions>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the display preferences.
+    /// </summary>
+    public DbSet<DisplayPreferences> DisplayPreferences => Set<DisplayPreferences>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the image infos.
+    /// </summary>
+    public DbSet<ImageInfo> ImageInfos => Set<ImageInfo>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the item display preferences.
+    /// </summary>
+    public DbSet<ItemDisplayPreferences> ItemDisplayPreferences => Set<ItemDisplayPreferences>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the custom item display preferences.
+    /// </summary>
+    public DbSet<CustomItemDisplayPreferences> CustomItemDisplayPreferences => Set<CustomItemDisplayPreferences>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the permissions.
+    /// </summary>
+    public DbSet<Permission> Permissions => Set<Permission>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the preferences.
+    /// </summary>
+    public DbSet<Preference> Preferences => Set<Preference>();
+
+    /// <summary>
+    /// Gets the <see cref="DbSet{TEntity}"/> containing the users.
+    /// </summary>
+    public DbSet<User> Users => Set<User>();
+
+    /*public DbSet<Artwork> Artwork => Set<Artwork>();
+
+    public DbSet<Book> Books => Set<Book>();
+
+    public DbSet<BookMetadata> BookMetadata => Set<BookMetadata>();
+
+    public DbSet<Chapter> Chapters => Set<Chapter>();
+
+    public DbSet<Collection> Collections => Set<Collection>();
+
+    public DbSet<CollectionItem> CollectionItems => Set<CollectionItem>();
+
+    public DbSet<Company> Companies => Set<Company>();
+
+    public DbSet<CompanyMetadata> CompanyMetadata => Set<CompanyMetadata>();
+
+    public DbSet<CustomItem> CustomItems => Set<CustomItem>();
+
+    public DbSet<CustomItemMetadata> CustomItemMetadata => Set<CustomItemMetadata>();
+
+    public DbSet<Episode> Episodes => Set<Episode>();
+
+    public DbSet<EpisodeMetadata> EpisodeMetadata => Set<EpisodeMetadata>();
+
+    public DbSet<Genre> Genres => Set<Genre>();
+
+    public DbSet<Group> Groups => Set<Groups>();
+
+    public DbSet<Library> Libraries => Set<Library>();
+
+    public DbSet<LibraryItem> LibraryItems => Set<LibraryItems>();
+
+    public DbSet<LibraryRoot> LibraryRoot => Set<LibraryRoot>();
+
+    public DbSet<MediaFile> MediaFiles => Set<MediaFiles>();
+
+    public DbSet<MediaFileStream> MediaFileStream => Set<MediaFileStream>();
+
+    public DbSet<Metadata> Metadata => Set<Metadata>();
+
+    public DbSet<MetadataProvider> MetadataProviders => Set<MetadataProvider>();
+
+    public DbSet<MetadataProviderId> MetadataProviderIds => Set<MetadataProviderId>();
+
+    public DbSet<Movie> Movies => Set<Movie>();
+
+    public DbSet<MovieMetadata> MovieMetadata => Set<MovieMetadata>();
+
+    public DbSet<MusicAlbum> MusicAlbums => Set<MusicAlbum>();
+
+    public DbSet<MusicAlbumMetadata> MusicAlbumMetadata => Set<MusicAlbumMetadata>();
+
+    public DbSet<Person> People => Set<Person>();
+
+    public DbSet<PersonRole> PersonRoles => Set<PersonRole>();
+
+    public DbSet<Photo> Photo => Set<Photo>();
+
+    public DbSet<PhotoMetadata> PhotoMetadata => Set<PhotoMetadata>();
+
+    public DbSet<ProviderMapping> ProviderMappings => Set<ProviderMapping>();
+
+    public DbSet<Rating> Ratings => Set<Rating>();
+
+    /// <summary>
+    /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to
+    /// store review ratings, not age ratings.
+    /// </summary>
+    public DbSet<RatingSource> RatingSources => Set<RatingSource>();
+
+    public DbSet<Release> Releases => Set<Release>();
+
+    public DbSet<Season> Seasons => Set<Season>();
+
+    public DbSet<SeasonMetadata> SeasonMetadata => Set<SeasonMetadata>();
+
+    public DbSet<Series> Series => Set<Series>();
+
+    public DbSet<SeriesMetadata> SeriesMetadata => Set<SeriesMetadata();
+
+    public DbSet<Track> Tracks => Set<Track>();
+
+    public DbSet<TrackMetadata> TrackMetadata => Set<TrackMetadata>();*/
+
+    /// <inheritdoc/>
+    public override int SaveChanges()
+    {
+        foreach (var saveEntity in ChangeTracker.Entries()
+                     .Where(e => e.State == EntityState.Modified)
+                     .Select(entry => entry.Entity)
+                     .OfType<IHasConcurrencyToken>())
+        {
+            saveEntity.OnSavingChanges();
+        }
+
+        return base.SaveChanges();
+    }
+
+    /// <inheritdoc />
+    protected override void OnModelCreating(ModelBuilder modelBuilder)
+    {
+        modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
+        base.OnModelCreating(modelBuilder);
+
+        // Configuration for each entity is in it's own class inside 'ModelConfiguration'.
+        modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDbContext).Assembly);
+    }
+}

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20200514181226_AddActivityLog.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20200514181226_AddActivityLog")]
     partial class AddActivityLog
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20200613202153_AddUsers.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20200613202153_AddUsers")]
     partial class AddUsers
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20200728005145_AddDisplayPreferences")]
     partial class AddDisplayPreferences
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20200905220533_FixDisplayPreferencesIndex")]
     partial class FixDisplayPreferencesIndex
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20201004171403_AddMaxActiveSessions")]
     partial class AddMaxActiveSessions
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs

@@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20201204223655_AddCustomDisplayPreferences")]
     partial class AddCustomDisplayPreferences
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20210320181425_AddIndexesAndCollations")]
     partial class AddIndexesAndCollations
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20210407110544_NullableCustomPrefValue.Designer.cs

@@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20210407110544_NullableCustomPrefValue")]
     partial class NullableCustomPrefValue
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20210814002109_AddDevices.Designer.cs

@@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20210814002109_AddDevices")]
     partial class AddDevices
     {

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/20221022080052_AddIndexActivityLogsDateCreated.Designer.cs

@@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     [Migration("20221022080052_AddIndexActivityLogsDateCreated")]
     partial class AddIndexActivityLogsDateCreated
     {

+ 5 - 5
Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs

@@ -4,17 +4,17 @@ using Microsoft.EntityFrameworkCore.Design;
 namespace Jellyfin.Server.Implementations.Migrations
 {
     /// <summary>
-    /// The design time factory for <see cref="JellyfinDb"/>.
+    /// The design time factory for <see cref="JellyfinDbContext"/>.
     /// This is only used for the creation of migrations and not during runtime.
     /// </summary>
-    internal class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDb>
+    internal class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDbContext>
     {
-        public JellyfinDb CreateDbContext(string[] args)
+        public JellyfinDbContext CreateDbContext(string[] args)
         {
-            var optionsBuilder = new DbContextOptionsBuilder<JellyfinDb>();
+            var optionsBuilder = new DbContextOptionsBuilder<JellyfinDbContext>();
             optionsBuilder.UseSqlite("Data Source=jellyfin.db");
 
-            return new JellyfinDb(optionsBuilder.Options);
+            return new JellyfinDbContext(optionsBuilder.Options);
         }
     }
 }

+ 1 - 1
Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs

@@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 
 namespace Jellyfin.Server.Implementations.Migrations
 {
-    [DbContext(typeof(JellyfinDb))]
+    [DbContext(typeof(JellyfinDbContext))]
     partial class JellyfinDbModelSnapshot : ModelSnapshot
     {
         protected override void BuildModel(ModelBuilder modelBuilder)

+ 2 - 4
Jellyfin.Server.Implementations/Security/AuthenticationManager.cs

@@ -10,13 +10,13 @@ namespace Jellyfin.Server.Implementations.Security
     /// <inheritdoc />
     public class AuthenticationManager : IAuthenticationManager
     {
-        private readonly IDbContextFactory<JellyfinDb> _dbProvider;
+        private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="AuthenticationManager"/> class.
         /// </summary>
         /// <param name="dbProvider">The database provider.</param>
-        public AuthenticationManager(IDbContextFactory<JellyfinDb> dbProvider)
+        public AuthenticationManager(IDbContextFactory<JellyfinDbContext> dbProvider)
         {
             _dbProvider = dbProvider;
         }
@@ -40,7 +40,6 @@ namespace Jellyfin.Server.Implementations.Security
             await using (dbContext.ConfigureAwait(false))
             {
                 return await dbContext.ApiKeys
-                    .AsAsyncEnumerable()
                     .Select(key => new AuthenticationInfo
                     {
                         AppName = key.Name,
@@ -60,7 +59,6 @@ namespace Jellyfin.Server.Implementations.Security
             await using (dbContext.ConfigureAwait(false))
             {
                 var key = await dbContext.ApiKeys
-                    .AsQueryable()
                     .Where(apiKey => apiKey.AccessToken == accessToken)
                     .FirstOrDefaultAsync()
                     .ConfigureAwait(false);

+ 2 - 2
Jellyfin.Server.Implementations/Security/AuthorizationContext.cs

@@ -16,12 +16,12 @@ namespace Jellyfin.Server.Implementations.Security
 {
     public class AuthorizationContext : IAuthorizationContext
     {
-        private readonly IDbContextFactory<JellyfinDb> _jellyfinDbProvider;
+        private readonly IDbContextFactory<JellyfinDbContext> _jellyfinDbProvider;
         private readonly IUserManager _userManager;
         private readonly IServerApplicationHost _serverApplicationHost;
 
         public AuthorizationContext(
-            IDbContextFactory<JellyfinDb> jellyfinDb,
+            IDbContextFactory<JellyfinDbContext> jellyfinDb,
             IUserManager userManager,
             IServerApplicationHost serverApplicationHost)
         {

+ 2 - 5
Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs

@@ -15,13 +15,13 @@ namespace Jellyfin.Server.Implementations.Users
     /// </summary>
     public class DisplayPreferencesManager : IDisplayPreferencesManager
     {
-        private readonly JellyfinDb _dbContext;
+        private readonly JellyfinDbContext _dbContext;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class.
         /// </summary>
         /// <param name="dbContextFactory">The database context factory.</param>
-        public DisplayPreferencesManager(IDbContextFactory<JellyfinDb> dbContextFactory)
+        public DisplayPreferencesManager(IDbContextFactory<JellyfinDbContext> dbContextFactory)
         {
             _dbContext = dbContextFactory.CreateDbContext();
         }
@@ -62,7 +62,6 @@ namespace Jellyfin.Server.Implementations.Users
         public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
         {
             return _dbContext.ItemDisplayPreferences
-                .AsQueryable()
                 .Where(prefs => prefs.UserId.Equals(userId) && !prefs.ItemId.Equals(default) && string.Equals(prefs.Client, client))
                 .ToList();
         }
@@ -71,7 +70,6 @@ namespace Jellyfin.Server.Implementations.Users
         public Dictionary<string, string?> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client)
         {
             return _dbContext.CustomItemDisplayPreferences
-                .AsQueryable()
                 .Where(prefs => prefs.UserId.Equals(userId)
                                 && prefs.ItemId.Equals(itemId)
                                 && string.Equals(prefs.Client, client))
@@ -82,7 +80,6 @@ namespace Jellyfin.Server.Implementations.Users
         public void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string?> customPreferences)
         {
             var existingPrefs = _dbContext.CustomItemDisplayPreferences
-                .AsQueryable()
                 .Where(prefs => prefs.UserId.Equals(userId)
                                 && prefs.ItemId.Equals(itemId)
                                 && string.Equals(prefs.Client, client));

+ 5 - 5
Jellyfin.Server.Implementations/Users/UserManager.cs

@@ -33,7 +33,7 @@ namespace Jellyfin.Server.Implementations.Users
     /// </summary>
     public class UserManager : IUserManager
     {
-        private readonly IDbContextFactory<JellyfinDb> _dbProvider;
+        private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
         private readonly IEventManager _eventManager;
         private readonly ICryptoProvider _cryptoProvider;
         private readonly INetworkManager _networkManager;
@@ -59,7 +59,7 @@ namespace Jellyfin.Server.Implementations.Users
         /// <param name="imageProcessor">The image processor.</param>
         /// <param name="logger">The logger.</param>
         public UserManager(
-            IDbContextFactory<JellyfinDb> dbProvider,
+            IDbContextFactory<JellyfinDbContext> dbProvider,
             IEventManager eventManager,
             ICryptoProvider cryptoProvider,
             INetworkManager networkManager,
@@ -85,6 +85,7 @@ namespace Jellyfin.Server.Implementations.Users
             _users = new ConcurrentDictionary<Guid, User>();
             using var dbContext = _dbProvider.CreateDbContext();
             foreach (var user in dbContext.Users
+                .AsSplitQuery()
                 .Include(user => user.Permissions)
                 .Include(user => user.Preferences)
                 .Include(user => user.AccessSchedules)
@@ -143,7 +144,6 @@ namespace Jellyfin.Server.Implementations.Users
             await using (dbContext.ConfigureAwait(false))
             {
                 if (await dbContext.Users
-                        .AsQueryable()
                         .AnyAsync(u => u.Username == newName && !u.Id.Equals(user.Id))
                         .ConfigureAwait(false))
                 {
@@ -172,7 +172,7 @@ namespace Jellyfin.Server.Implementations.Users
             }
         }
 
-        internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext)
+        internal async Task<User> CreateUserInternalAsync(string name, JellyfinDbContext dbContext)
         {
             // TODO: Remove after user item data is migrated.
             var max = await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false)
@@ -886,7 +886,7 @@ namespace Jellyfin.Server.Implementations.Users
             await UpdateUserAsync(user).ConfigureAwait(false);
         }
 
-        private async Task UpdateUserInternalAsync(JellyfinDb dbContext, User user)
+        private async Task UpdateUserInternalAsync(JellyfinDbContext dbContext, User user)
         {
             dbContext.Users.Update(user);
             _users[user.Id] = user;

+ 1 - 1
Jellyfin.Server/CoreAppHost.cs

@@ -107,7 +107,7 @@ namespace Jellyfin.Server
             yield return typeof(CoreAppHost).Assembly;
 
             // Jellyfin.Server.Implementations
-            yield return typeof(JellyfinDb).Assembly;
+            yield return typeof(JellyfinDbContext).Assembly;
         }
 
         /// <inheritdoc />

+ 2 - 2
Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs

@@ -19,7 +19,7 @@ namespace Jellyfin.Server.Migrations.Routines
         private const string DbFilename = "activitylog.db";
 
         private readonly ILogger<MigrateActivityLogDb> _logger;
-        private readonly IDbContextFactory<JellyfinDb> _provider;
+        private readonly IDbContextFactory<JellyfinDbContext> _provider;
         private readonly IServerApplicationPaths _paths;
 
         /// <summary>
@@ -28,7 +28,7 @@ namespace Jellyfin.Server.Migrations.Routines
         /// <param name="logger">The logger.</param>
         /// <param name="paths">The server application paths.</param>
         /// <param name="provider">The database provider.</param>
-        public MigrateActivityLogDb(ILogger<MigrateActivityLogDb> logger, IServerApplicationPaths paths, IDbContextFactory<JellyfinDb> provider)
+        public MigrateActivityLogDb(ILogger<MigrateActivityLogDb> logger, IServerApplicationPaths paths, IDbContextFactory<JellyfinDbContext> provider)
         {
             _logger = logger;
             _provider = provider;

+ 2 - 2
Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs

@@ -20,7 +20,7 @@ namespace Jellyfin.Server.Migrations.Routines
         private const string DbFilename = "authentication.db";
 
         private readonly ILogger<MigrateAuthenticationDb> _logger;
-        private readonly IDbContextFactory<JellyfinDb> _dbProvider;
+        private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IUserManager _userManager;
 
@@ -33,7 +33,7 @@ namespace Jellyfin.Server.Migrations.Routines
         /// <param name="userManager">The user manager.</param>
         public MigrateAuthenticationDb(
             ILogger<MigrateAuthenticationDb> logger,
-            IDbContextFactory<JellyfinDb> dbProvider,
+            IDbContextFactory<JellyfinDbContext> dbProvider,
             IServerApplicationPaths appPaths,
             IUserManager userManager)
         {

+ 2 - 2
Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs

@@ -25,7 +25,7 @@ namespace Jellyfin.Server.Migrations.Routines
 
         private readonly ILogger<MigrateDisplayPreferencesDb> _logger;
         private readonly IServerApplicationPaths _paths;
-        private readonly IDbContextFactory<JellyfinDb> _provider;
+        private readonly IDbContextFactory<JellyfinDbContext> _provider;
         private readonly JsonSerializerOptions _jsonOptions;
         private readonly IUserManager _userManager;
 
@@ -39,7 +39,7 @@ namespace Jellyfin.Server.Migrations.Routines
         public MigrateDisplayPreferencesDb(
             ILogger<MigrateDisplayPreferencesDb> logger,
             IServerApplicationPaths paths,
-            IDbContextFactory<JellyfinDb> provider,
+            IDbContextFactory<JellyfinDbContext> provider,
             IUserManager userManager)
         {
             _logger = logger;

+ 2 - 2
Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs

@@ -27,7 +27,7 @@ namespace Jellyfin.Server.Migrations.Routines
 
         private readonly ILogger<MigrateUserDb> _logger;
         private readonly IServerApplicationPaths _paths;
-        private readonly IDbContextFactory<JellyfinDb> _provider;
+        private readonly IDbContextFactory<JellyfinDbContext> _provider;
         private readonly IXmlSerializer _xmlSerializer;
 
         /// <summary>
@@ -40,7 +40,7 @@ namespace Jellyfin.Server.Migrations.Routines
         public MigrateUserDb(
             ILogger<MigrateUserDb> logger,
             IServerApplicationPaths paths,
-            IDbContextFactory<JellyfinDb> provider,
+            IDbContextFactory<JellyfinDbContext> provider,
             IXmlSerializer xmlSerializer)
         {
             _logger = logger;

+ 1 - 1
Jellyfin.Server/Program.cs

@@ -247,7 +247,7 @@ namespace Jellyfin.Server
                 {
                     _logger.LogInformation("Running query planner optimizations in the database... This might take a while");
                     // Run before disposing the application
-                    var context = await appHost.ServiceProvider.GetRequiredService<IDbContextFactory<JellyfinDb>>().CreateDbContextAsync().ConfigureAwait(false);
+                    var context = await appHost.ServiceProvider.GetRequiredService<IDbContextFactory<JellyfinDbContext>>().CreateDbContextAsync().ConfigureAwait(false);
                     await using (context.ConfigureAwait(false))
                     {
                         if (context.Database.IsSqlite())

+ 1 - 1
Jellyfin.Server/Startup.cs

@@ -119,7 +119,7 @@ namespace Jellyfin.Server
                 .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
 
             services.AddHealthChecks()
-                .AddCheck<DbContextFactoryHealthCheck<JellyfinDb>>(nameof(JellyfinDb));
+                .AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
 
             services.AddHlsPlaylistGenerator();
         }