Baustein 3: Repositories verdrahten Teil A (Kapitel 10)

OnChange-Hook auf den 19 einfachen Repositories (keine Kaskaden/Batches)
ergaenzt: SeatingPlan, GroupMembership, GradingKeyTemplate, Grade,
GradingScheme, ReportGrade, Unit, Lesson, WorkTask, TimeEntry,
ParticipationAspect, ParticipationSection, Subject, ShorthandCode,
AlternativeLessonPath, TimetableSlot, SchoolHoliday, SupervisionDuty,
SubstitutionEntry. Mechanisch, ein Aufruf nach dem bestehenden
Upsert/Delete.

Tabellengetriebener Test statt 19 fast identischer Testdateien.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 11:22:46 +02:00
co-authored by Claude Sonnet 5
parent 831cc1c16c
commit ed34e5d036
2 changed files with 296 additions and 13 deletions
+92 -13
View File
@@ -132,6 +132,7 @@ public class SeatingPlanRepository(LiteDbContext db) : ISeatingPlanRepository
plan.UpdatedAt = DateTime.UtcNow;
db.SeatingPlans.Upsert(plan);
db.OnChange?.Invoke(nameof(SeatingPlan), plan.Id.ToString(), "Save", plan);
}
public void Delete(Guid id)
@@ -139,6 +140,7 @@ public class SeatingPlanRepository(LiteDbContext db) : ISeatingPlanRepository
if (db.SeatingPlans.FindById(id) is { } plan)
ArchivedGroupWriteGuard.EnsureActive(db, plan.GroupId);
db.SeatingPlans.Delete(id);
db.OnChange?.Invoke(nameof(SeatingPlan), id.ToString(), "Delete", null);
}
}
@@ -157,12 +159,14 @@ public class GroupMembershipRepository(LiteDbContext db) : IGroupMembershipRepos
if (existing is not null && existing.Id != membership.Id)
throw new InvalidOperationException("Der Schüler ist dieser Lerngruppe bereits zugeordnet.");
db.Memberships.Upsert(membership);
db.OnChange?.Invoke(nameof(GroupMembership), membership.Id.ToString(), "Save", membership);
}
public void Delete(Guid id)
{
if (db.Memberships.FindById(id) is { } membership)
ArchivedGroupWriteGuard.EnsureActive(db, membership.GroupId);
db.Memberships.Delete(id);
db.OnChange?.Invoke(nameof(GroupMembership), id.ToString(), "Delete", null);
}
}
@@ -221,8 +225,17 @@ public class GradingKeyTemplateRepository(LiteDbContext db) : IGradingKeyTemplat
public List<GradingKeyTemplate> GetByGradingSystem(GradingSystem system) =>
db.GradingKeyTemplates.Find(t => t.GradingSystem == system).OrderBy(t => t.Name).ToList();
public GradingKeyTemplate? GetById(Guid id) => db.GradingKeyTemplates.FindById(id);
public void Save(GradingKeyTemplate t) { t.UpdatedAt = DateTime.UtcNow; db.GradingKeyTemplates.Upsert(t); }
public void Delete(Guid id) => db.GradingKeyTemplates.Delete(id);
public void Save(GradingKeyTemplate t)
{
t.UpdatedAt = DateTime.UtcNow;
db.GradingKeyTemplates.Upsert(t);
db.OnChange?.Invoke(nameof(GradingKeyTemplate), t.Id.ToString(), "Save", t);
}
public void Delete(Guid id)
{
db.GradingKeyTemplates.Delete(id);
db.OnChange?.Invoke(nameof(GradingKeyTemplate), id.ToString(), "Delete", null);
}
}
public class GradeRepository(LiteDbContext db) : IGradeRepository
@@ -235,12 +248,14 @@ public class GradeRepository(LiteDbContext db) : IGradeRepository
{
ArchivedGroupWriteGuard.EnsureActive(db, g.GroupId);
db.Grades.Upsert(g);
db.OnChange?.Invoke(nameof(Grade), g.Id.ToString(), "Save", g);
}
public void Delete(Guid id)
{
if (db.Grades.FindById(id) is { } grade)
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
db.Grades.Delete(id);
db.OnChange?.Invoke(nameof(Grade), id.ToString(), "Delete", null);
}
}
@@ -254,12 +269,14 @@ public class GradingSchemeRepository(LiteDbContext db) : IGradingSchemeRepositor
if (s.GroupId is Guid groupId) ArchivedGroupWriteGuard.EnsureActive(db, groupId);
s.UpdatedAt = DateTime.UtcNow;
db.GradingSchemes.Upsert(s);
db.OnChange?.Invoke(nameof(GradingScheme), s.Id.ToString(), "Save", s);
}
public void Delete(Guid id)
{
if (db.GradingSchemes.FindById(id)?.GroupId is Guid groupId)
ArchivedGroupWriteGuard.EnsureActive(db, groupId);
db.GradingSchemes.Delete(id);
db.OnChange?.Invoke(nameof(GradingScheme), id.ToString(), "Delete", null);
}
}
@@ -273,12 +290,14 @@ public class ReportGradeRepository(LiteDbContext db) : IReportGradeRepository
ArchivedGroupWriteGuard.EnsureActive(db, r.GroupId);
r.UpdatedAt = DateTime.UtcNow;
db.ReportGrades.Upsert(r);
db.OnChange?.Invoke(nameof(ReportGrade), r.Id.ToString(), "Save", r);
}
public void Delete(Guid id)
{
if (db.ReportGrades.FindById(id) is { } grade)
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
db.ReportGrades.Delete(id);
db.OnChange?.Invoke(nameof(ReportGrade), id.ToString(), "Delete", null);
}
}
@@ -292,12 +311,14 @@ public class UnitRepository(LiteDbContext db) : IUnitRepository
ArchivedGroupWriteGuard.EnsureActive(db, u.GroupId);
u.UpdatedAt = DateTime.UtcNow;
db.Units.Upsert(u);
db.OnChange?.Invoke(nameof(Unit), u.Id.ToString(), "Save", u);
}
public void Delete(Guid id)
{
if (db.Units.FindById(id) is { } unit)
ArchivedGroupWriteGuard.EnsureActive(db, unit.GroupId);
db.Units.Delete(id);
db.OnChange?.Invoke(nameof(Unit), id.ToString(), "Delete", null);
}
}
@@ -315,12 +336,14 @@ public class LessonRepository(LiteDbContext db) : ILessonRepository
ArchivedGroupWriteGuard.EnsureActive(db, l.GroupId);
l.UpdatedAt = DateTime.UtcNow;
db.Lessons.Upsert(l);
db.OnChange?.Invoke(nameof(Lesson), l.Id.ToString(), "Save", l);
}
public void Delete(Guid id)
{
if (db.Lessons.FindById(id) is { } lesson)
ArchivedGroupWriteGuard.EnsureActive(db, lesson.GroupId);
db.Lessons.Delete(id);
db.OnChange?.Invoke(nameof(Lesson), id.ToString(), "Delete", null);
}
}
@@ -357,8 +380,17 @@ public class WorkTaskRepository(LiteDbContext db) : IWorkTaskRepository
db.Tasks.Find(t => t.Status == s).OrderBy(t => t.DueDate).ToList();
public List<WorkTask> GetAll() =>
db.Tasks.FindAll().OrderBy(t => t.Status).ThenBy(t => t.DueDate).ToList();
public void Save(WorkTask t) { t.UpdatedAt = DateTime.UtcNow; db.Tasks.Upsert(t); }
public void Delete(Guid id) => db.Tasks.Delete(id);
public void Save(WorkTask t)
{
t.UpdatedAt = DateTime.UtcNow;
db.Tasks.Upsert(t);
db.OnChange?.Invoke(nameof(WorkTask), t.Id.ToString(), "Save", t);
}
public void Delete(Guid id)
{
db.Tasks.Delete(id);
db.OnChange?.Invoke(nameof(WorkTask), id.ToString(), "Delete", null);
}
}
public class TimeEntryRepository(LiteDbContext db) : ITimeEntryRepository
@@ -369,8 +401,16 @@ public class TimeEntryRepository(LiteDbContext db) : ITimeEntryRepository
db.TimeEntries.Find(e => e.Date >= from && e.Date <= to).OrderBy(e => e.Date).ToList();
public List<TimeEntry> GetByTask(Guid id) =>
db.TimeEntries.Find(e => e.TaskId == id).ToList();
public void Save(TimeEntry e) => db.TimeEntries.Upsert(e);
public void Delete(Guid id) => db.TimeEntries.Delete(id);
public void Save(TimeEntry e)
{
db.TimeEntries.Upsert(e);
db.OnChange?.Invoke(nameof(TimeEntry), e.Id.ToString(), "Save", e);
}
public void Delete(Guid id)
{
db.TimeEntries.Delete(id);
db.OnChange?.Invoke(nameof(TimeEntry), id.ToString(), "Delete", null);
}
}
public class ParticipationSessionRepository(LiteDbContext db) : IParticipationSessionRepository
@@ -453,12 +493,14 @@ public class ParticipationAspectRepository(LiteDbContext db) : IParticipationAsp
throw new InvalidOperationException("Ein Aspekt mit diesem Schlüssel existiert für diese Gruppe bereits.");
a.UpdatedAt = DateTime.UtcNow;
db.ParticipationAspects.Upsert(a);
db.OnChange?.Invoke(nameof(ParticipationAspect), a.Id.ToString(), "Save", a);
}
public void Delete(Guid id)
{
if (db.ParticipationAspects.FindById(id)?.GroupId is Guid groupId)
ArchivedGroupWriteGuard.EnsureActive(db, groupId);
db.ParticipationAspects.Delete(id);
db.OnChange?.Invoke(nameof(ParticipationAspect), id.ToString(), "Delete", null);
}
}
@@ -470,12 +512,14 @@ public class ParticipationSectionRepository(LiteDbContext db) : IParticipationSe
{
ArchivedGroupWriteGuard.EnsureActive(db, s.GroupId);
db.ParticipationSections.Upsert(s);
db.OnChange?.Invoke(nameof(ParticipationSection), s.Id.ToString(), "Save", s);
}
public void Delete(Guid id)
{
if (db.ParticipationSections.FindById(id) is { } section)
ArchivedGroupWriteGuard.EnsureActive(db, section.GroupId);
db.ParticipationSections.Delete(id);
db.OnChange?.Invoke(nameof(ParticipationSection), id.ToString(), "Delete", null);
}
}
@@ -495,12 +539,14 @@ public class SubjectRepository(LiteDbContext db) : ISubjectRepository
throw new InvalidOperationException("Ein Fach mit diesem Namen existiert bereits.");
s.UpdatedAt = DateTime.UtcNow;
db.Subjects.Upsert(s);
db.OnChange?.Invoke(nameof(Subject), s.Id.ToString(), "Save", s);
}
public void Delete(Guid id)
{
if (db.Groups.Exists(g => g.SubjectId == id) || db.CompetencyDomains.Exists(d => d.SubjectId == id))
throw new InvalidOperationException("Das Fach wird noch von einer Lerngruppe oder einem Kompetenzkatalog verwendet.");
db.Subjects.Delete(id);
db.OnChange?.Invoke(nameof(Subject), id.ToString(), "Delete", null);
}
}
@@ -518,8 +564,13 @@ public class ShorthandCodeRepository(LiteDbContext db) : IShorthandCodeRepositor
throw new InvalidOperationException("Ein Kürzel mit diesem Code existiert bereits.");
c.UpdatedAt = DateTime.UtcNow;
db.ShorthandCodes.Upsert(c);
db.OnChange?.Invoke(nameof(ShorthandCode), c.Id.ToString(), "Save", c);
}
public void Delete(Guid id)
{
db.ShorthandCodes.Delete(id);
db.OnChange?.Invoke(nameof(ShorthandCode), id.ToString(), "Delete", null);
}
public void Delete(Guid id) => db.ShorthandCodes.Delete(id);
}
public class AlternativeLessonPathRepository(LiteDbContext db) : IAlternativeLessonPathRepository
@@ -537,8 +588,13 @@ public class AlternativeLessonPathRepository(LiteDbContext db) : IAlternativeLes
throw new InvalidOperationException("Ein alternativer Ablauf mit diesem Namen existiert bereits.");
p.UpdatedAt = DateTime.UtcNow;
db.AlternativeLessonPaths.Upsert(p);
db.OnChange?.Invoke(nameof(AlternativeLessonPath), p.Id.ToString(), "Save", p);
}
public void Delete(Guid id)
{
db.AlternativeLessonPaths.Delete(id);
db.OnChange?.Invoke(nameof(AlternativeLessonPath), id.ToString(), "Delete", null);
}
public void Delete(Guid id) => db.AlternativeLessonPaths.Delete(id);
}
public class TimetableSlotRepository(LiteDbContext db) : ITimetableSlotRepository
@@ -555,20 +611,30 @@ public class TimetableSlotRepository(LiteDbContext db) : ITimetableSlotRepositor
if (occupied is not null && occupied.Id != slot.Id)
throw new InvalidOperationException("Diese Stunde ist bereits belegt.");
db.TimetableSlots.Upsert(slot);
db.OnChange?.Invoke(nameof(TimetableSlot), slot.Id.ToString(), "Save", slot);
}
public void Delete(Guid id)
{
if (db.TimetableSlots.FindById(id) is { } slot)
ArchivedGroupWriteGuard.EnsureActive(db, slot.GroupId);
db.TimetableSlots.Delete(id);
db.OnChange?.Invoke(nameof(TimetableSlot), id.ToString(), "Delete", null);
}
}
public class SchoolHolidayRepository(LiteDbContext db) : ISchoolHolidayRepository
{
public List<SchoolHoliday> GetAll() => db.SchoolHolidays.FindAll().OrderBy(h => h.StartDate).ToList();
public void Save(SchoolHoliday holiday) => db.SchoolHolidays.Upsert(holiday);
public void Delete(Guid id) => db.SchoolHolidays.Delete(id);
public void Save(SchoolHoliday holiday)
{
db.SchoolHolidays.Upsert(holiday);
db.OnChange?.Invoke(nameof(SchoolHoliday), holiday.Id.ToString(), "Save", holiday);
}
public void Delete(Guid id)
{
db.SchoolHolidays.Delete(id);
db.OnChange?.Invoke(nameof(SchoolHoliday), id.ToString(), "Delete", null);
}
}
public class SupervisionDutyRepository(LiteDbContext db) : ISupervisionDutyRepository
@@ -582,8 +648,13 @@ public class SupervisionDutyRepository(LiteDbContext db) : ISupervisionDutyRepos
if (occupied is not null && occupied.Id != duty.Id)
throw new InvalidOperationException("Für diese Pause ist bereits eine Aufsicht eingetragen.");
db.SupervisionDuties.Upsert(duty);
db.OnChange?.Invoke(nameof(SupervisionDuty), duty.Id.ToString(), "Save", duty);
}
public void Delete(Guid id)
{
db.SupervisionDuties.Delete(id);
db.OnChange?.Invoke(nameof(SupervisionDuty), id.ToString(), "Delete", null);
}
public void Delete(Guid id) => db.SupervisionDuties.Delete(id);
}
public class SubstitutionEntryRepository(LiteDbContext db) : ISubstitutionEntryRepository
@@ -591,8 +662,16 @@ public class SubstitutionEntryRepository(LiteDbContext db) : ISubstitutionEntryR
public List<SubstitutionEntry> GetAll() => db.SubstitutionEntries.FindAll().OrderBy(e => e.Date).ToList();
public List<SubstitutionEntry> GetByDate(DateOnly date) =>
db.SubstitutionEntries.Find(e => e.Date == date).ToList();
public void Save(SubstitutionEntry entry) => db.SubstitutionEntries.Upsert(entry);
public void Delete(Guid id) => db.SubstitutionEntries.Delete(id);
public void Save(SubstitutionEntry entry)
{
db.SubstitutionEntries.Upsert(entry);
db.OnChange?.Invoke(nameof(SubstitutionEntry), entry.Id.ToString(), "Save", entry);
}
public void Delete(Guid id)
{
db.SubstitutionEntries.Delete(id);
db.OnChange?.Invoke(nameof(SubstitutionEntry), id.ToString(), "Delete", null);
}
}
public class CompetencyDomainRepository(LiteDbContext db) : ICompetencyDomainRepository