feat: add MergePeople to person repository

Reassigns albums (PersonOwnerId), faces (PersonId), and maintainers
from source people to destination, then hard-deletes source people.
This commit is contained in:
2026-07-16 17:56:24 +02:00
parent 5e1306e466
commit 656e6fa9bf
2 changed files with 41 additions and 0 deletions
@@ -89,6 +89,14 @@ public interface IPersonRepository : IDisposable {
/// <returns>A collection of matching people.</returns>
IEnumerable<Person> FindBulk(IEnumerable<Guid> ids);
/// <summary>
/// Merges multiple source people into a destination person.
/// Albums, faces, and maintainers are reassigned to the destination, then source people are hard-deleted.
/// </summary>
/// <param name="destId">The ID of the destination person.</param>
/// <param name="sourceIds">The IDs of the source people to merge.</param>
void MergePeople(Guid destId, List<Guid> sourceIds);
/// <summary>
/// Removes a person from the database.
/// </summary>
+33
View File
@@ -227,6 +227,39 @@ public class PersonRepository(LactoseDbContext context) : IPersonRepository {
}
}
/// <inheritdoc />
public void MergePeople(Guid destId, List<Guid> sourceIds) {
var dest = context.People
.AsSplitQuery()
.Include(p => p.Maintainers)
.FirstOrDefault(p => p.Id == destId);
if (dest == null) return;
// Reassign albums
var albums = context.Albums.Where(a => sourceIds.Contains(a.PersonOwnerId ?? Guid.Empty)).ToList();
foreach (var album in albums)
album.PersonOwnerId = destId;
// Reassign faces
var faces = context.Faces.Where(f => f.PersonId.HasValue && sourceIds.Contains(f.PersonId.Value)).ToList();
foreach (var face in faces)
face.PersonId = destId;
// Reassign maintainers
var existingMaintainerIds = dest.Maintainers?.Select(m => m.Id).ToHashSet() ?? [];
var sourceMaintainers = context.PersonMaintainers
.Where(pm => sourceIds.Contains(pm.PersonId))
.ToList();
foreach (var pm in sourceMaintainers) {
if (!existingMaintainerIds.Contains(pm.UserId))
context.PersonMaintainers.Add(new PersonMaintainer { PersonId = destId, UserId = pm.UserId });
}
// Hard-delete source people
var people = context.People.Where(p => sourceIds.Contains(p.Id)).ToList();
context.People.RemoveRange(people);
}
/// <inheritdoc />
public void Dispose() => context.Dispose();
}