fix: paginate PersonRepository.SearchQuery by ID before loading albums

Include + Skip/Take on a collection navigation can produce duplicate people when sorted by album count, because pagination operates on joined rows. Fix by selecting paged IDs first, then loading the full entities with Include for those IDs.
This commit is contained in:
REDCODE
2026-07-11 20:47:44 +02:00
parent 41c262d157
commit ee3511c09a

View File

@@ -59,7 +59,7 @@ public class PersonRepository(LactoseDbContext context) : IPersonRepository {
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<Person> SearchQuery(string query, int page = 0, int pageSize = 30, string? sortBy = null, bool sortAsc = true, Guid userId = default, EAccessLevel accessLevel = EAccessLevel.User) { public IEnumerable<Person> SearchQuery(string query, int page = 0, int pageSize = 30, string? sortBy = null, bool sortAsc = true, Guid userId = default, EAccessLevel accessLevel = EAccessLevel.User) {
IQueryable<Person> peopleQuery = context.People.Include(p => p.Albums); IQueryable<Person> peopleQuery = context.People;
if (!string.IsNullOrEmpty(query)) if (!string.IsNullOrEmpty(query))
peopleQuery = peopleQuery.Where(p => EF.Functions.ILike(p.Name, $"%{query}%")); peopleQuery = peopleQuery.Where(p => EF.Functions.ILike(p.Name, $"%{query}%"));
@@ -80,9 +80,19 @@ public class PersonRepository(LactoseDbContext context) : IPersonRepository {
_ => sortAsc ? peopleQuery.OrderBy(p => p.Name) : peopleQuery.OrderByDescending(p => p.Name), _ => sortAsc ? peopleQuery.OrderBy(p => p.Name) : peopleQuery.OrderByDescending(p => p.Name),
}; };
return ordered var pagedIds = ordered
.Select(p => p.Id)
.Skip(page * pageSize) .Skip(page * pageSize)
.Take(pageSize); .Take(pageSize)
.ToList();
var pagedPeople = context.People
.Include(p => p.Albums)
.Where(p => pagedIds.Contains(p.Id))
.ToList();
var idOrder = pagedIds.Select((id, i) => (id, i)).ToDictionary(x => x.id, x => x.i);
return [.. pagedPeople.OrderBy(p => idOrder.GetValueOrDefault(p.Id))];
} }
/// <inheritdoc /> /// <inheritdoc />