mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-29 11:58:27 +01:00
Expanded People architecture and fixed migration
This commit is contained in:
@@ -81,7 +81,8 @@ public sealed class BaseItemRepository(
|
||||
|
||||
using var context = dbProvider.CreateDbContext();
|
||||
using var transaction = context.Database.BeginTransaction();
|
||||
context.Peoples.Where(e => e.ItemId == id).ExecuteDelete();
|
||||
context.PeopleBaseItemMap.Where(e => e.ItemId == id).ExecuteDelete();
|
||||
context.Peoples.Where(e => e.BaseItems!.Count == 0).ExecuteDelete();
|
||||
context.Chapters.Where(e => e.ItemId == id).ExecuteDelete();
|
||||
context.MediaStreamInfos.Where(e => e.ItemId == id).ExecuteDelete();
|
||||
context.AncestorIds.Where(e => e.ItemId == id).ExecuteDelete();
|
||||
@@ -602,13 +603,13 @@ public sealed class BaseItemRepository(
|
||||
{
|
||||
baseQuery = baseQuery
|
||||
.Where(e =>
|
||||
context.Peoples.Where(w => context.BaseItems.Where(r => filter.PersonIds.Contains(r.Id)).Any(f => f.Name == w.Name))
|
||||
context.PeopleBaseItemMap.Where(w => context.BaseItems.Where(r => filter.PersonIds.Contains(r.Id)).Any(f => f.Name == w.People.Name))
|
||||
.Any(f => f.ItemId == e.Id));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.Person))
|
||||
{
|
||||
baseQuery = baseQuery.Where(e => e.Peoples!.Any(f => f.Name == filter.Person));
|
||||
baseQuery = baseQuery.Where(e => e.Peoples!.Any(f => f.People.Name == filter.Person));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.MinSortName))
|
||||
@@ -934,7 +935,7 @@ public sealed class BaseItemRepository(
|
||||
if (filter.IsDeadPerson.HasValue && filter.IsDeadPerson.Value)
|
||||
{
|
||||
baseQuery = baseQuery
|
||||
.Where(e => !e.Peoples!.Any(f => f.Name == e.Name));
|
||||
.Where(e => !e.Peoples!.Any(f => f.People.Name == e.Name));
|
||||
}
|
||||
|
||||
if (filter.Years.Length == 1)
|
||||
|
||||
@@ -10,6 +10,7 @@ using MediaBrowser.Controller.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Item;
|
||||
#pragma warning disable RS0030 // Do not use banned APIs
|
||||
|
||||
/// <summary>
|
||||
/// Manager for handling people.
|
||||
@@ -28,7 +29,7 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
var dbQuery = TranslateQuery(context.Peoples.AsNoTracking(), context, filter);
|
||||
|
||||
dbQuery = dbQuery.OrderBy(e => e.ListOrder);
|
||||
// dbQuery = dbQuery.OrderBy(e => e.ListOrder);
|
||||
if (filter.Limit > 0)
|
||||
{
|
||||
dbQuery = dbQuery.Take(filter.Limit);
|
||||
@@ -43,7 +44,7 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
var dbQuery = TranslateQuery(context.Peoples.AsNoTracking(), context, filter);
|
||||
|
||||
dbQuery = dbQuery.OrderBy(e => e.ListOrder);
|
||||
// dbQuery = dbQuery.OrderBy(e => e.ListOrder);
|
||||
if (filter.Limit > 0)
|
||||
{
|
||||
dbQuery = dbQuery.Take(filter.Limit);
|
||||
@@ -58,7 +59,29 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
using var transaction = context.Database.BeginTransaction();
|
||||
|
||||
context.Peoples.Where(e => e.ItemId.Equals(itemId)).ExecuteDelete();
|
||||
context.PeopleBaseItemMap.Where(e => e.ItemId == itemId).ExecuteDelete();
|
||||
foreach (var item in people)
|
||||
{
|
||||
var personEntity = Map(item);
|
||||
var existingEntity = context.Peoples.FirstOrDefault(e => e.Id == personEntity.Id);
|
||||
if (existingEntity is null)
|
||||
{
|
||||
context.Peoples.Add(personEntity);
|
||||
existingEntity = personEntity;
|
||||
}
|
||||
|
||||
context.PeopleBaseItemMap.Add(new PeopleBaseItemMap()
|
||||
{
|
||||
Item = null!,
|
||||
ItemId = itemId,
|
||||
People = existingEntity,
|
||||
PeopleId = existingEntity.Id,
|
||||
ListOrder = item.SortOrder,
|
||||
SortOrder = item.SortOrder,
|
||||
Role = item.Role
|
||||
});
|
||||
}
|
||||
|
||||
context.Peoples.AddRange(people.Select(Map));
|
||||
context.SaveChanges();
|
||||
transaction.Commit();
|
||||
@@ -68,10 +91,8 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
{
|
||||
var personInfo = new PersonInfo()
|
||||
{
|
||||
ItemId = people.ItemId,
|
||||
Id = people.Id,
|
||||
Name = people.Name,
|
||||
Role = people.Role,
|
||||
SortOrder = people.SortOrder,
|
||||
};
|
||||
if (Enum.TryParse<PersonKind>(people.PersonType, out var kind))
|
||||
{
|
||||
@@ -85,13 +106,9 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
{
|
||||
var personInfo = new People()
|
||||
{
|
||||
ItemId = people.ItemId,
|
||||
Name = people.Name,
|
||||
Role = people.Role,
|
||||
SortOrder = people.SortOrder,
|
||||
PersonType = people.Type.ToString(),
|
||||
Item = null!,
|
||||
ListOrder = people.SortOrder
|
||||
Id = people.Id,
|
||||
};
|
||||
|
||||
return personInfo;
|
||||
@@ -108,12 +125,12 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
|
||||
if (!filter.ItemId.IsEmpty())
|
||||
{
|
||||
query = query.Where(e => e.ItemId.Equals(filter.ItemId));
|
||||
query = query.Where(e => e.BaseItems!.Any(w => w.ItemId.Equals(filter.ItemId)));
|
||||
}
|
||||
|
||||
if (!filter.AppearsInItemId.IsEmpty())
|
||||
{
|
||||
query = query.Where(e => context.Peoples.Where(f => f.ItemId.Equals(filter.AppearsInItemId)).Select(e => e.Name).Contains(e.Name));
|
||||
query = query.Where(e => e.BaseItems!.Any(w => w.ItemId.Equals(filter.AppearsInItemId)));
|
||||
}
|
||||
|
||||
var queryPersonTypes = filter.PersonTypes.Where(IsValidPersonType).ToList();
|
||||
@@ -129,9 +146,9 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider) :
|
||||
query = query.Where(e => !queryPersonTypes.Contains(e.PersonType));
|
||||
}
|
||||
|
||||
if (filter.MaxListOrder.HasValue)
|
||||
if (filter.MaxListOrder.HasValue && !filter.ItemId.IsEmpty())
|
||||
{
|
||||
query = query.Where(e => e.ListOrder <= filter.MaxListOrder.Value);
|
||||
query = query.Where(e => e.BaseItems!.First(w => w.ItemId == filter.ItemId).ListOrder <= filter.MaxListOrder.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.NameContains))
|
||||
|
||||
@@ -112,7 +112,7 @@ public class JellyfinDbContext(DbContextOptions<JellyfinDbContext> options, ILog
|
||||
public DbSet<Chapter> Chapters => Set<Chapter>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DbSet{TEntity}"/> containing the user data.
|
||||
/// Gets the <see cref="DbSet{TEntity}"/>.
|
||||
/// </summary>
|
||||
public DbSet<ItemValue> ItemValues => Set<ItemValue>();
|
||||
|
||||
@@ -122,15 +122,20 @@ public class JellyfinDbContext(DbContextOptions<JellyfinDbContext> options, ILog
|
||||
public DbSet<ItemValueMap> ItemValuesMap => Set<ItemValueMap>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DbSet{TEntity}"/> containing the user data.
|
||||
/// Gets the <see cref="DbSet{TEntity}"/>.
|
||||
/// </summary>
|
||||
public DbSet<MediaStreamInfo> MediaStreamInfos => Set<MediaStreamInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DbSet{TEntity}"/> containing the user data.
|
||||
/// Gets the <see cref="DbSet{TEntity}"/>.
|
||||
/// </summary>
|
||||
public DbSet<People> Peoples => Set<People>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DbSet{TEntity}"/>.
|
||||
/// </summary>
|
||||
public DbSet<PeopleBaseItemMap> PeopleBaseItemMap => Set<PeopleBaseItemMap>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DbSet{TEntity}"/> containing the referenced Providers with ids.
|
||||
/// </summary>
|
||||
|
||||
1613
Jellyfin.Server.Implementations/Migrations/20241011095125_LibraryPeopleMigration.Designer.cs
generated
Normal file
1613
Jellyfin.Server.Implementations/Migrations/20241011095125_LibraryPeopleMigration.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class LibraryPeopleMigration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Peoples_BaseItems_ItemId",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Peoples",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Peoples_ItemId_ListOrder",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ListOrder",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SortOrder",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "ItemId",
|
||||
table: "Peoples",
|
||||
newName: "Id");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Role",
|
||||
table: "Peoples",
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "TEXT");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Peoples",
|
||||
table: "Peoples",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PeopleBaseItemMap",
|
||||
columns: table => new
|
||||
{
|
||||
ItemId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
PeopleId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
SortOrder = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
ListOrder = table.Column<int>(type: "INTEGER", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PeopleBaseItemMap", x => new { x.ItemId, x.PeopleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_PeopleBaseItemMap_BaseItems_ItemId",
|
||||
column: x => x.ItemId,
|
||||
principalTable: "BaseItems",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_PeopleBaseItemMap_Peoples_PeopleId",
|
||||
column: x => x.PeopleId,
|
||||
principalTable: "Peoples",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PeopleBaseItemMap_ItemId_ListOrder",
|
||||
table: "PeopleBaseItemMap",
|
||||
columns: new[] { "ItemId", "ListOrder" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PeopleBaseItemMap_ItemId_SortOrder",
|
||||
table: "PeopleBaseItemMap",
|
||||
columns: new[] { "ItemId", "SortOrder" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PeopleBaseItemMap_PeopleId",
|
||||
table: "PeopleBaseItemMap",
|
||||
column: "PeopleId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PeopleBaseItemMap");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Peoples",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Id",
|
||||
table: "Peoples",
|
||||
newName: "ItemId");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Role",
|
||||
table: "Peoples",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: string.Empty,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "TEXT",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ListOrder",
|
||||
table: "Peoples",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SortOrder",
|
||||
table: "Peoples",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Peoples",
|
||||
table: "Peoples",
|
||||
columns: new[] { "ItemId", "Role", "ListOrder" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Peoples_ItemId_ListOrder",
|
||||
table: "Peoples",
|
||||
columns: new[] { "ItemId", "ListOrder" });
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Peoples_BaseItems_ItemId",
|
||||
table: "Peoples",
|
||||
column: "ItemId",
|
||||
principalTable: "BaseItems",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
1613
Jellyfin.Server.Implementations/Migrations/20241011100757_LibraryPeopleRoleMigration.Designer.cs
generated
Normal file
1613
Jellyfin.Server.Implementations/Migrations/20241011100757_LibraryPeopleRoleMigration.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class LibraryPeopleRoleMigration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Role",
|
||||
table: "Peoples");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Role",
|
||||
table: "PeopleBaseItemMap",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Role",
|
||||
table: "PeopleBaseItemMap");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Role",
|
||||
table: "Peoples",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -911,15 +911,10 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.People", b =>
|
||||
{
|
||||
b.Property<Guid>("ItemId")
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ListOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
@@ -927,16 +922,39 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.Property<string>("PersonType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ItemId", "Role", "ListOrder");
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name");
|
||||
|
||||
b.ToTable("Peoples");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b =>
|
||||
{
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("PeopleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ListOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ItemId", "PeopleId");
|
||||
|
||||
b.HasIndex("PeopleId");
|
||||
|
||||
b.HasIndex("ItemId", "ListOrder");
|
||||
|
||||
b.ToTable("Peoples");
|
||||
b.HasIndex("ItemId", "SortOrder");
|
||||
|
||||
b.ToTable("PeopleBaseItemMap");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
@@ -1473,7 +1491,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.People", b =>
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item")
|
||||
.WithMany("Peoples")
|
||||
@@ -1481,7 +1499,15 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Jellyfin.Data.Entities.People", "People")
|
||||
.WithMany("BaseItems")
|
||||
.HasForeignKey("PeopleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
|
||||
b.Navigation("People");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
@@ -1559,6 +1585,11 @@ namespace Jellyfin.Server.Implementations.Migrations
|
||||
b.Navigation("BaseItemsMap");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.People", b =>
|
||||
{
|
||||
b.Navigation("BaseItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("AccessSchedules");
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.ModelConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// People configuration.
|
||||
/// </summary>
|
||||
public class PeopleBaseItemMapConfiguration : IEntityTypeConfiguration<PeopleBaseItemMap>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void Configure(EntityTypeBuilder<PeopleBaseItemMap> builder)
|
||||
{
|
||||
builder.HasKey(e => new { e.ItemId, e.PeopleId });
|
||||
builder.HasIndex(e => new { e.ItemId, e.SortOrder });
|
||||
builder.HasIndex(e => new { e.ItemId, e.ListOrder });
|
||||
builder.HasOne(e => e.Item);
|
||||
builder.HasOne(e => e.People);
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,8 @@ public class PeopleConfiguration : IEntityTypeConfiguration<People>
|
||||
/// <inheritdoc/>
|
||||
public void Configure(EntityTypeBuilder<People> builder)
|
||||
{
|
||||
builder.HasKey(e => new { e.ItemId, e.Role, e.ListOrder });
|
||||
builder.HasIndex(e => new { e.ItemId, e.ListOrder });
|
||||
builder.HasKey(e => e.Id);
|
||||
builder.HasIndex(e => e.Name);
|
||||
builder.HasMany(e => e.BaseItems);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user