diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-07-26 09:56:49 +0200 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-07-26 09:56:49 +0200 |
| commit | f3a1d56c563c71573ed2e7681b347533897ee70c (patch) | |
| tree | e167ba022a2de32de1baaaa1f57329cce8936f01 | |
| parent | 766be1e8bb9f35009d81d1fe429ac7ee500bd688 (diff) | |
Use DistinctBy where possible
3 files changed, 18 insertions, 29 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs index 24892fef92..8e917f6951 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs @@ -208,7 +208,7 @@ public sealed partial class BaseItemRepository if (isMusicArtist) { // For MusicArtist, prefer the entity from a library the user can actually access. - // Materilaize to prevent correlated per-group first-row queries which hurt performance. + // Materialize to prevent correlated per-group first-row queries which hurt performance. var topParentIds = filter.TopParentIds; representativeIds = masterQuery .Select(e => new { e.Id, e.PresentationUniqueKey, e.TopParentId }) diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.Querying.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.Querying.cs index 00af0bcbeb..1ff8d8f863 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.Querying.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.Querying.cs @@ -134,19 +134,13 @@ public sealed partial class BaseItemRepository .ThenByDescending(e => e.Id) .Select(e => new { e.Id, e.PresentationUniqueKey }); - var seenKeys = new HashSet<string>(); - var firstIds = new List<Guid>(limit ?? 0); - foreach (var row in orderedIds.AsEnumerable()) - { - if (seenKeys.Add(row.PresentationUniqueKey!)) - { - firstIds.Add(row.Id); - if (limit.HasValue && firstIds.Count >= limit.Value) - { - break; - } - } - } + // DistinctBy and Take are lazy, so enumeration stops as soon as limit distinct keys are read. + var firstIds = orderedIds + .AsEnumerable() + .DistinctBy(row => row.PresentationUniqueKey) + .Select(row => row.Id) + .Take(limit ?? int.MaxValue) + .ToList(); return LoadLatestByIds(context, firstIds, filter); } diff --git a/Jellyfin.Server.Implementations/Item/NextUpService.cs b/Jellyfin.Server.Implementations/Item/NextUpService.cs index 725b4cfaac..f478daef23 100644 --- a/Jellyfin.Server.Implementations/Item/NextUpService.cs +++ b/Jellyfin.Server.Implementations/Item/NextUpService.cs @@ -98,7 +98,7 @@ public class NextUpService : INextUpService .Where(e => e.UserData!.Any(ud => ud.UserId == userId && ud.Played)); lastWatchedBase = _queryHelpers.ApplyAccessFiltering(context, lastWatchedBase, filter); - // Use lightweight projection + client-side grouping to avoid correlated scalar subquery + // Use lightweight projection + client-side dedup to avoid the correlated scalar subquery // per group that EF generates for GroupBy+OrderByDescending+FirstOrDefault. var allPlayedLite = lastWatchedBase .Select(e => new @@ -110,15 +110,11 @@ public class NextUpService : INextUpService }) .ToList(); - var lastWatchedInfo = new Dictionary<string, Guid>(); - foreach (var group in allPlayedLite.GroupBy(e => e.SeriesPresentationUniqueKey)) - { - var lastWatched = group - .OrderByDescending(e => e.ParentIndexNumber) - .ThenByDescending(e => e.IndexNumber) - .First(); - lastWatchedInfo[group.Key!] = lastWatched.Id; - } + var lastWatchedInfo = allPlayedLite + .OrderByDescending(e => e.ParentIndexNumber) + .ThenByDescending(e => e.IndexNumber) + .DistinctBy(e => e.SeriesPresentationUniqueKey) + .ToDictionary(e => e.SeriesPresentationUniqueKey!, e => e.Id); Dictionary<string, Guid> lastWatchedByDateInfo = new(); if (includeWatchedForRewatching) @@ -144,11 +140,10 @@ public class NextUpService : INextUpService (e, ud) => new { EpisodeId = e.Id, e.SeriesPresentationUniqueKey, ud.LastPlayedDate }) .ToList(); - foreach (var group in playedWithDates.GroupBy(x => x.SeriesPresentationUniqueKey)) - { - var mostRecent = group.OrderByDescending(x => x.LastPlayedDate).First(); - lastWatchedByDateInfo[group.Key!] = mostRecent.EpisodeId; - } + lastWatchedByDateInfo = playedWithDates + .OrderByDescending(x => x.LastPlayedDate) + .DistinctBy(x => x.SeriesPresentationUniqueKey) + .ToDictionary(x => x.SeriesPresentationUniqueKey!, x => x.EpisodeId); } var allLastWatchedIds = lastWatchedInfo.Values |
