using System; using Jellyfin.Database.Implementations.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Jellyfin.Database.Implementations.ModelConfiguration; /// /// Configuration for BaseItem. /// public class BaseItemConfiguration : IEntityTypeConfiguration { /// public void Configure(EntityTypeBuilder builder) { builder.HasKey(e => e.Id); // TODO: See rant in entity file. // builder.HasOne(e => e.Parent).WithMany(e => e.DirectChildren).HasForeignKey(e => e.ParentId); // builder.HasOne(e => e.TopParent).WithMany(e => e.AllChildren).HasForeignKey(e => e.TopParentId); // builder.HasOne(e => e.Season).WithMany(e => e.SeasonEpisodes).HasForeignKey(e => e.SeasonId); // builder.HasOne(e => e.Series).WithMany(e => e.SeriesEpisodes).HasForeignKey(e => e.SeriesId); builder.HasMany(e => e.Peoples); builder.HasMany(e => e.UserData); builder.HasMany(e => e.ItemValues); builder.HasMany(e => e.MediaStreams); builder.HasMany(e => e.Chapters); builder.HasMany(e => e.Provider); builder.HasMany(e => e.Parents); builder.HasMany(e => e.Children); builder.HasMany(e => e.DirectChildren).WithOne(e => e.DirectParent).HasForeignKey(e => e.ParentId).OnDelete(DeleteBehavior.Cascade); builder.HasMany(e => e.Extras).WithOne(e => e.Owner).HasForeignKey(e => e.OwnerId).OnDelete(DeleteBehavior.NoAction); builder.HasMany(e => e.LockedFields); builder.HasMany(e => e.TrailerTypes); builder.HasMany(e => e.Images); builder.HasIndex(e => e.Path); builder.HasIndex(e => e.ParentId); builder.HasIndex(e => e.OwnerId); builder.HasIndex(e => e.Name); builder.HasIndex(e => new { e.ExtraType, e.OwnerId }); builder.HasIndex(e => e.PresentationUniqueKey); // covering index builder.HasIndex(e => new { e.TopParentId, e.Id }); // series builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.PresentationUniqueKey, e.SortName }); // series counts // seriesdateplayed sort order builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.IsFolder, e.IsVirtualItem }); // live tv programs builder.HasIndex(e => new { e.Type, e.TopParentId, e.StartDate }); // covering index for getitemvalues builder.HasIndex(e => new { e.Type, e.TopParentId, e.Id }); // used by movie suggestions builder.HasIndex(e => new { e.Type, e.TopParentId, e.PresentationUniqueKey }); // latest items builder.HasIndex(e => new { e.Type, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); builder.HasIndex(e => new { e.IsFolder, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated }); // latest items - optimized for sorting by DateCreated (no PresentationUniqueKey breaking the sort) builder.HasIndex(e => new { e.TopParentId, e.Type, e.IsVirtualItem, e.DateCreated }); builder.HasIndex(e => new { e.TopParentId, e.IsFolder, e.IsVirtualItem, e.DateCreated }); builder.HasIndex(e => new { e.TopParentId, e.MediaType, e.IsVirtualItem, e.DateCreated }); // resume builder.HasIndex(e => new { e.MediaType, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey }); // sorted library queries (e.g., Series sorted by SortName) builder.HasIndex(e => new { e.Type, e.TopParentId, e.SortName }); // NextUp: per-series episode ordering (index seek + range scan on season/episode) builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.ParentIndexNumber, e.IndexNumber }); // ByName queries: WHERE Type = X AND CleanName IN (...) builder.HasIndex(e => new { e.Type, e.CleanName }); // Latest TV: GROUP BY SeriesName builder.HasIndex(e => e.SeriesName); // Latest TV: episode count per season, season count per series builder.HasIndex(e => e.SeasonId); builder.HasIndex(e => e.SeriesId); // Items/Counts: SELECT Type, COUNT(*) GROUP BY Type filtered by TopParentId. builder.HasIndex(e => new { e.TopParentId, e.Type, e.IsVirtualItem }) .HasFilter("\"PrimaryVersionId\" IS NULL AND (\"OwnerId\" IS NULL OR \"ExtraType\" IS NOT NULL)"); builder.HasData(new BaseItemEntity() { Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), Type = "PLACEHOLDER", Name = "This is a placeholder item for UserData that has been detached from its original item", }); } }