Kapitel 7 abgeschlossen.

This commit is contained in:
2026-08-16 00:29:01 +02:00
parent da8d2bb1da
commit f9e398b225
47 changed files with 2636 additions and 107 deletions
+172 -21
View File
@@ -3,6 +3,18 @@ using LehrerApp.Core.Models;
namespace LehrerApp.Data.Repositories;
internal static class ArchivedGroupWriteGuard
{
public const string Message =
"Diese Lerngruppe ist archiviert. Bitte reaktiviere sie, bevor du Änderungen vornimmst.";
public static void EnsureActive(LiteDbContext db, Guid groupId)
{
if (db.Groups.FindById(groupId) is { IsActive: false })
throw new InvalidOperationException(Message);
}
}
public class StudentRepository(LiteDbContext db) : IStudentRepository
{
public Student? GetById(Guid id) => db.Students.FindById(id);
@@ -16,8 +28,22 @@ public class StudentRepository(LiteDbContext db) : IStudentRepository
.Select(e => e.StudentId).ToHashSet();
return db.Students.Find(s => ids.Contains(s.Id)).OrderBy(s => s.LastName).ToList();
}
public StudentReferenceSummary GetReferenceSummary(Guid studentId) => new(
db.Memberships.Count(m => m.StudentId == studentId),
db.ExamResults.Count(r => r.StudentId == studentId),
db.Grades.Count(g => g.StudentId == studentId),
db.ReportGrades.Count(g => g.StudentId == studentId),
db.ParticipationEntries.Count(e => e.StudentId == studentId),
db.Documentation.Count(d => d.StudentId == studentId));
public void Save(Student s) { s.UpdatedAt = DateTime.UtcNow; db.Students.Upsert(s); }
public void Delete(Guid id) => db.Students.Delete(id);
public void Delete(Guid id)
{
var references = GetReferenceSummary(id);
if (references.HasReferences)
throw new InvalidOperationException(
"Der Schüler besitzt verknüpfte Daten und kann nur deaktiviert werden.");
db.Students.Delete(id);
}
}
public class GroupRepository(LiteDbContext db) : IGroupRepository
@@ -33,6 +59,16 @@ public class GroupRepository(LiteDbContext db) : IGroupRepository
.OrderBy(g => g.Name).ToList();
public void Save(LearningGroup g)
{
var existing = db.Groups.FindById(g.Id);
if (existing is { IsActive: false } && !g.IsActive)
throw new InvalidOperationException(ArchivedGroupWriteGuard.Message);
if (existing is { IsActive: false } && g.IsActive
&& (existing.Name != g.Name || existing.Type != g.Type || existing.SubjectId != g.SubjectId
|| existing.SchoolYear != g.SchoolYear || existing.GradeLevel != g.GradeLevel
|| existing.GradingSystem != g.GradingSystem || existing.HoursPerWeek != g.HoursPerWeek
|| existing.IsOwnClass != g.IsOwnClass || existing.IsDifferentiated != g.IsDifferentiated))
throw new InvalidOperationException(
"Bitte reaktiviere die Lerngruppe zuerst und nimm die Änderungen anschließend vor.");
if (g.SubjectId is Guid subjectId && db.Subjects.FindById(subjectId) is null)
throw new InvalidOperationException("Das gewählte Fach existiert nicht mehr.");
g.UpdatedAt = DateTime.UtcNow;
@@ -40,6 +76,7 @@ public class GroupRepository(LiteDbContext db) : IGroupRepository
}
public void Delete(Guid id)
{
ArchivedGroupWriteGuard.EnsureActive(db, id);
db.ExecuteInTransaction(() =>
{
foreach (var membership in db.Memberships.Find(e => e.GroupId == id).ToList())
@@ -121,12 +158,18 @@ public class GroupMembershipRepository(LiteDbContext db) : IGroupMembershipRepos
db.Memberships.FindOne(e => e.StudentId == studentId && e.GroupId == groupId);
public void Save(GroupMembership membership)
{
ArchivedGroupWriteGuard.EnsureActive(db, membership.GroupId);
var existing = GetByStudentAndGroup(membership.StudentId, membership.GroupId);
if (existing is not null && existing.Id != membership.Id)
throw new InvalidOperationException("Der Schüler ist dieser Lerngruppe bereits zugeordnet.");
db.Memberships.Upsert(membership);
}
public void Delete(Guid id) => db.Memberships.Delete(id);
public void Delete(Guid id)
{
if (db.Memberships.FindById(id) is { } membership)
ArchivedGroupWriteGuard.EnsureActive(db, membership.GroupId);
db.Memberships.Delete(id);
}
}
public class ExamRepository(LiteDbContext db) : IExamRepository
@@ -135,9 +178,16 @@ public class ExamRepository(LiteDbContext db) : IExamRepository
public List<Exam> GetAll() => db.Exams.FindAll().OrderBy(e => e.Date).ToList();
public List<Exam> GetByGroup(Guid groupId) =>
db.Exams.Find(e => e.GroupId == groupId).OrderByDescending(e => e.Date).ToList();
public void Save(Exam e) { e.UpdatedAt = DateTime.UtcNow; db.Exams.Upsert(e); }
public void Save(Exam e)
{
ArchivedGroupWriteGuard.EnsureActive(db, e.GroupId);
e.UpdatedAt = DateTime.UtcNow;
db.Exams.Upsert(e);
}
public void Delete(Guid id)
{
if (db.Exams.FindById(id) is { } exam)
ArchivedGroupWriteGuard.EnsureActive(db, exam.GroupId);
foreach (var result in db.ExamResults.Find(r => r.ExamId == id).ToList())
db.ExamResults.Delete(result.Id);
db.Exams.Delete(id);
@@ -152,9 +202,18 @@ public class ExamResultRepository(LiteDbContext db) : IExamResultRepository
db.ExamResults.Find(r => r.StudentId == id).ToList();
public ExamResult? GetByExamAndStudent(Guid examId, Guid studentId) =>
db.ExamResults.FindOne(r => r.ExamId == examId && r.StudentId == studentId);
public void Save(ExamResult r) { r.UpdatedAt = DateTime.UtcNow; db.ExamResults.Upsert(r); }
public void Save(ExamResult r)
{
if (db.Exams.FindById(r.ExamId) is { } exam)
ArchivedGroupWriteGuard.EnsureActive(db, exam.GroupId);
r.UpdatedAt = DateTime.UtcNow;
db.ExamResults.Upsert(r);
}
public void SaveMany(List<ExamResult> results)
{
foreach (var examId in results.Select(r => r.ExamId).Distinct())
if (db.Exams.FindById(examId) is { } exam)
ArchivedGroupWriteGuard.EnsureActive(db, exam.GroupId);
var now = DateTime.UtcNow;
foreach (var r in results) r.UpdatedAt = now;
db.ExamResults.Upsert(results);
@@ -178,8 +237,17 @@ public class GradeRepository(LiteDbContext db) : IGradeRepository
db.Grades.Find(g => g.StudentId == sid && g.GroupId == gid).OrderBy(g => g.Date).ToList();
public List<Grade> GetByGroup(Guid id) =>
db.Grades.Find(g => g.GroupId == id).OrderBy(g => g.Date).ToList();
public void Save(Grade g) => db.Grades.Upsert(g);
public void Delete(Guid id) => db.Grades.Delete(id);
public void Save(Grade g)
{
ArchivedGroupWriteGuard.EnsureActive(db, g.GroupId);
db.Grades.Upsert(g);
}
public void Delete(Guid id)
{
if (db.Grades.FindById(id) is { } grade)
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
db.Grades.Delete(id);
}
}
public class GradingSchemeRepository(LiteDbContext db) : IGradingSchemeRepository
@@ -187,8 +255,18 @@ public class GradingSchemeRepository(LiteDbContext db) : IGradingSchemeRepositor
public GradingScheme? GetByGroup(Guid groupId) => db.GradingSchemes.FindOne(s => s.GroupId == groupId);
public GradingScheme? GetDefaultForType(GroupType type) =>
db.GradingSchemes.FindOne(s => s.GroupId == null && s.GroupType == type);
public void Save(GradingScheme s) { s.UpdatedAt = DateTime.UtcNow; db.GradingSchemes.Upsert(s); }
public void Delete(Guid id) => db.GradingSchemes.Delete(id);
public void Save(GradingScheme s)
{
if (s.GroupId is Guid groupId) ArchivedGroupWriteGuard.EnsureActive(db, groupId);
s.UpdatedAt = DateTime.UtcNow;
db.GradingSchemes.Upsert(s);
}
public void Delete(Guid id)
{
if (db.GradingSchemes.FindById(id)?.GroupId is Guid groupId)
ArchivedGroupWriteGuard.EnsureActive(db, groupId);
db.GradingSchemes.Delete(id);
}
}
public class ReportGradeRepository(LiteDbContext db) : IReportGradeRepository
@@ -196,8 +274,18 @@ public class ReportGradeRepository(LiteDbContext db) : IReportGradeRepository
public List<ReportGrade> GetByGroup(Guid groupId) => db.ReportGrades.Find(r => r.GroupId == groupId).ToList();
public ReportGrade? GetByStudentGroupPeriod(Guid studentId, Guid groupId, string period) =>
db.ReportGrades.FindOne(r => r.StudentId == studentId && r.GroupId == groupId && r.Period == period);
public void Save(ReportGrade r) { r.UpdatedAt = DateTime.UtcNow; db.ReportGrades.Upsert(r); }
public void Delete(Guid id) => db.ReportGrades.Delete(id);
public void Save(ReportGrade r)
{
ArchivedGroupWriteGuard.EnsureActive(db, r.GroupId);
r.UpdatedAt = DateTime.UtcNow;
db.ReportGrades.Upsert(r);
}
public void Delete(Guid id)
{
if (db.ReportGrades.FindById(id) is { } grade)
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
db.ReportGrades.Delete(id);
}
}
public class UnitRepository(LiteDbContext db) : IUnitRepository
@@ -205,8 +293,18 @@ public class UnitRepository(LiteDbContext db) : IUnitRepository
public Unit? GetById(Guid id) => db.Units.FindById(id);
public List<Unit> GetByGroup(Guid id) =>
db.Units.Find(u => u.GroupId == id).OrderBy(u => u.StartDate).ToList();
public void Save(Unit u) { u.UpdatedAt = DateTime.UtcNow; db.Units.Upsert(u); }
public void Delete(Guid id) => db.Units.Delete(id);
public void Save(Unit u)
{
ArchivedGroupWriteGuard.EnsureActive(db, u.GroupId);
u.UpdatedAt = DateTime.UtcNow;
db.Units.Upsert(u);
}
public void Delete(Guid id)
{
if (db.Units.FindById(id) is { } unit)
ArchivedGroupWriteGuard.EnsureActive(db, unit.GroupId);
db.Units.Delete(id);
}
}
public class LessonRepository(LiteDbContext db) : ILessonRepository
@@ -218,8 +316,18 @@ public class LessonRepository(LiteDbContext db) : ILessonRepository
public List<Lesson> GetByGroupAndRange(Guid gid, DateOnly from, DateOnly to) =>
db.Lessons.Find(l => l.GroupId == gid && l.Date >= from && l.Date <= to)
.OrderBy(l => l.Date).ToList();
public void Save(Lesson l) { l.UpdatedAt = DateTime.UtcNow; db.Lessons.Upsert(l); }
public void Delete(Guid id) => db.Lessons.Delete(id);
public void Save(Lesson l)
{
ArchivedGroupWriteGuard.EnsureActive(db, l.GroupId);
l.UpdatedAt = DateTime.UtcNow;
db.Lessons.Upsert(l);
}
public void Delete(Guid id)
{
if (db.Lessons.FindById(id) is { } lesson)
ArchivedGroupWriteGuard.EnsureActive(db, lesson.GroupId);
db.Lessons.Delete(id);
}
}
public class DocumentationRepository(LiteDbContext db) : IDocumentationRepository
@@ -276,9 +384,16 @@ public class ParticipationSessionRepository(LiteDbContext db) : IParticipationSe
public List<ParticipationSession> GetByGroup(Guid groupId) =>
db.ParticipationSessions.Find(s => s.GroupId == groupId).OrderByDescending(s => s.Date).ToList();
public ParticipationSession? GetById(Guid id) => db.ParticipationSessions.FindById(id);
public void Save(ParticipationSession s) { s.UpdatedAt = DateTime.UtcNow; db.ParticipationSessions.Upsert(s); }
public void Save(ParticipationSession s)
{
ArchivedGroupWriteGuard.EnsureActive(db, s.GroupId);
s.UpdatedAt = DateTime.UtcNow;
db.ParticipationSessions.Upsert(s);
}
public void Delete(Guid id)
{
if (db.ParticipationSessions.FindById(id) is { } session)
ArchivedGroupWriteGuard.EnsureActive(db, session.GroupId);
db.ParticipationSessions.Delete(id);
foreach (var e in db.ParticipationEntries.Find(e => e.SessionId == id).ToList())
db.ParticipationEntries.Delete(e.Id);
@@ -293,15 +408,26 @@ public class ParticipationRepository(LiteDbContext db) : IParticipationRepositor
db.ParticipationEntries.Find(e => e.StudentId == studentId).ToList();
public ParticipationEntry? GetBySessionAndStudent(Guid sessionId, Guid studentId) =>
db.ParticipationEntries.FindOne(e => e.SessionId == sessionId && e.StudentId == studentId);
public void Save(ParticipationEntry e) { e.UpdatedAt = DateTime.UtcNow; db.ParticipationEntries.Upsert(e); }
public void Save(ParticipationEntry e)
{
if (db.ParticipationSessions.FindById(e.SessionId) is { } session)
ArchivedGroupWriteGuard.EnsureActive(db, session.GroupId);
e.UpdatedAt = DateTime.UtcNow;
db.ParticipationEntries.Upsert(e);
}
public void SaveMany(List<ParticipationEntry> entries)
{
foreach (var sessionId in entries.Select(e => e.SessionId).Distinct())
if (db.ParticipationSessions.FindById(sessionId) is { } session)
ArchivedGroupWriteGuard.EnsureActive(db, session.GroupId);
var now = DateTime.UtcNow;
foreach (var e in entries) e.UpdatedAt = now;
db.ParticipationEntries.Upsert(entries);
}
public void DeleteBySession(Guid sessionId)
{
if (db.ParticipationSessions.FindById(sessionId) is { } session)
ArchivedGroupWriteGuard.EnsureActive(db, session.GroupId);
foreach (var e in db.ParticipationEntries.Find(e => e.SessionId == sessionId).ToList())
db.ParticipationEntries.Delete(e.Id);
}
@@ -313,16 +439,35 @@ public class ParticipationAspectRepository(LiteDbContext db) : IParticipationAsp
db.ParticipationAspects.Find(a => a.GroupId == null && a.IsActive).OrderBy(a => a.SortOrder).ToList();
public List<ParticipationAspect> GetByGroup(Guid groupId) =>
db.ParticipationAspects.Find(a => a.GroupId == groupId && a.IsActive).OrderBy(a => a.SortOrder).ToList();
public void Save(ParticipationAspect a) { a.UpdatedAt = DateTime.UtcNow; db.ParticipationAspects.Upsert(a); }
public void Delete(Guid id) => db.ParticipationAspects.Delete(id);
public void Save(ParticipationAspect a)
{
if (a.GroupId is Guid groupId) ArchivedGroupWriteGuard.EnsureActive(db, groupId);
a.UpdatedAt = DateTime.UtcNow;
db.ParticipationAspects.Upsert(a);
}
public void Delete(Guid id)
{
if (db.ParticipationAspects.FindById(id)?.GroupId is Guid groupId)
ArchivedGroupWriteGuard.EnsureActive(db, groupId);
db.ParticipationAspects.Delete(id);
}
}
public class ParticipationSectionRepository(LiteDbContext db) : IParticipationSectionRepository
{
public List<ParticipationSection> GetByGroup(Guid groupId) =>
db.ParticipationSections.Find(s => s.GroupId == groupId).OrderBy(s => s.StartDate).ToList();
public void Save(ParticipationSection s) => db.ParticipationSections.Upsert(s);
public void Delete(Guid id) => db.ParticipationSections.Delete(id);
public void Save(ParticipationSection s)
{
ArchivedGroupWriteGuard.EnsureActive(db, s.GroupId);
db.ParticipationSections.Upsert(s);
}
public void Delete(Guid id)
{
if (db.ParticipationSections.FindById(id) is { } section)
ArchivedGroupWriteGuard.EnsureActive(db, section.GroupId);
db.ParticipationSections.Delete(id);
}
}
public class SubjectRepository(LiteDbContext db) : ISubjectRepository
@@ -395,13 +540,19 @@ public class TimetableSlotRepository(LiteDbContext db) : ITimetableSlotRepositor
db.TimetableSlots.Find(s => s.GroupId == groupId).OrderBy(s => s.Weekday).ThenBy(s => s.PeriodNumber).ToList();
public void Save(TimetableSlot slot)
{
ArchivedGroupWriteGuard.EnsureActive(db, slot.GroupId);
var occupied = db.TimetableSlots.FindAll()
.FirstOrDefault(s => s.Weekday == slot.Weekday && s.PeriodNumber == slot.PeriodNumber);
if (occupied is not null && occupied.Id != slot.Id)
throw new InvalidOperationException("Diese Stunde ist bereits belegt.");
db.TimetableSlots.Upsert(slot);
}
public void Delete(Guid id) => db.TimetableSlots.Delete(id);
public void Delete(Guid id)
{
if (db.TimetableSlots.FindById(id) is { } slot)
ArchivedGroupWriteGuard.EnsureActive(db, slot.GroupId);
db.TimetableSlots.Delete(id);
}
}
public class SchoolHolidayRepository(LiteDbContext db) : ISchoolHolidayRepository