diff options
| author | brandon <brandon@clinger.dev> | 2026-08-07 11:59:17 -0400 |
|---|---|---|
| committer | brandon <brandon@clinger.dev> | 2026-08-07 11:59:17 -0400 |
| commit | d6da6906a4b3426f05c5bf4ffe8bab4b2bc78ce8 (patch) | |
| tree | 78683665d1792916de8683b6ac5bc13e17904d87 /Jellyfin.Server.Implementations | |
| parent | 6c37a6ef8b4ce027e7ac2aaa827244711cf5f39c (diff) | |
Batch people lookups when building item DTOs
GetBaseItemDtos already batch fetches user data, child counts, played counts
and artists before its per item loop, but AttachPeople still ran one GetPeople
query per item. Rendering a page of items (for example a large playlist) fired
one extra query per row.
Add GetPeopleByItems to IPeopleRepository, which reads every requested item in a
single query over the people mapping table and returns full PersonInfo (role,
type and sort order) grouped by item id. GetBaseItemDtos prefetches this once
when the People field is requested and passes it into AttachPeople, which reads
from the batch instead of querying per item. The single item GetBaseItemDto path
keeps its existing per item behaviour when no batch is supplied.
Adds a DtoService test asserting people resolve from the batch and the per item
GetPeople is never called.
Diffstat (limited to 'Jellyfin.Server.Implementations')
| -rw-r--r-- | Jellyfin.Server.Implementations/Item/PeopleRepository.cs | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index 05c8bffd66..a592d0e6e2 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -236,6 +236,53 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I return result; } + /// <inheritdoc/> + public IReadOnlyDictionary<Guid, IReadOnlyList<PersonInfo>> GetPeopleByItems(IReadOnlyList<Guid> itemIds) + { + using var context = _dbProvider.CreateDbContext(); + var rows = context.PeopleBaseItemMap + .AsNoTracking() + .Where(m => itemIds.Contains(m.ItemId)) + .OrderBy(m => m.ListOrder) + .Select(m => new + { + m.ItemId, + m.Role, + m.SortOrder, + m.People.Id, + m.People.Name, + m.People.PersonType + }) + .ToList(); + + var result = new Dictionary<Guid, IReadOnlyList<PersonInfo>>(); + foreach (var group in rows.GroupBy(r => r.ItemId)) + { + var people = new List<PersonInfo>(); + foreach (var row in group) + { + var personInfo = new PersonInfo + { + ItemId = row.ItemId, + Id = row.Id, + Name = row.Name, + Role = row.Role, + SortOrder = row.SortOrder + }; + if (Enum.TryParse<PersonKind>(row.PersonType, out var kind)) + { + personInfo.Type = kind; + } + + people.Add(personInfo); + } + + result[group.Key] = people; + } + + return result; + } + private IEnumerable<PersonInfo> MapCredits(People people) { var mappings = people.BaseItems; |
