aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-07-26 09:56:49 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-07-26 09:56:49 +0200
commitf3a1d56c563c71573ed2e7681b347533897ee70c (patch)
treee167ba022a2de32de1baaaa1f57329cce8936f01
parent766be1e8bb9f35009d81d1fe429ac7ee500bd688 (diff)
Use DistinctBy where possible
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs2
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.Querying.cs20
-rw-r--r--Jellyfin.Server.Implementations/Item/NextUpService.cs25
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