aufräumen
This commit is contained in:
@@ -22,7 +22,7 @@ public class LiteDbContext : IDisposable
|
||||
|
||||
public ILiteCollection<Student> Students => _db.GetCollection<Student>("students");
|
||||
public ILiteCollection<LearningGroup> Groups => _db.GetCollection<LearningGroup>("groups");
|
||||
public ILiteCollection<Enrollment> Enrollments => _db.GetCollection<Enrollment>("enrollments");
|
||||
public ILiteCollection<GroupMembership> Memberships => _db.GetCollection<GroupMembership>("group_memberships");
|
||||
public ILiteCollection<Exam> Exams => _db.GetCollection<Exam>("exams");
|
||||
public ILiteCollection<ExamResult> ExamResults => _db.GetCollection<ExamResult>("exam_results");
|
||||
public ILiteCollection<Grade> Grades => _db.GetCollection<Grade>("grades");
|
||||
@@ -42,7 +42,11 @@ public class LiteDbContext : IDisposable
|
||||
|
||||
private void MigrateExistingData()
|
||||
{
|
||||
MigrateMemberships();
|
||||
RemoveRedundantLegacyFields();
|
||||
|
||||
var groups = _db.GetCollection<BsonDocument>("groups");
|
||||
var subjects = _db.GetCollection<Subject>("subjects");
|
||||
var missingArchiveState = groups.FindAll()
|
||||
.Where(g => !g.ContainsKey(nameof(LearningGroup.IsActive)))
|
||||
.ToList();
|
||||
@@ -51,6 +55,83 @@ public class LiteDbContext : IDisposable
|
||||
group[nameof(LearningGroup.IsActive)] = true;
|
||||
groups.Update(group);
|
||||
}
|
||||
|
||||
// Subject war anfangs nur als Text in der Gruppe gespeichert. Alte
|
||||
// Werte werden einmalig an die Fachstammdaten angebunden und danach
|
||||
// entfernt, damit es nur noch eine führende Fachbezeichnung gibt.
|
||||
foreach (var group in groups.FindAll().ToList())
|
||||
{
|
||||
var changed = false;
|
||||
var legacyName = group.TryGetValue("Subject", out var value) && value.IsString
|
||||
? value.AsString.Trim()
|
||||
: "";
|
||||
var hasSubjectId = group.TryGetValue(nameof(LearningGroup.SubjectId), out var id)
|
||||
&& id.IsGuid && subjects.FindById(id.AsGuid) is not null;
|
||||
|
||||
if (!hasSubjectId && legacyName.Length > 0)
|
||||
{
|
||||
var subject = subjects.FindAll().FirstOrDefault(s =>
|
||||
string.Equals(s.Name.Trim(), legacyName, StringComparison.OrdinalIgnoreCase));
|
||||
if (subject is null)
|
||||
{
|
||||
subject = new Subject { Name = legacyName };
|
||||
subjects.Insert(subject);
|
||||
}
|
||||
group[nameof(LearningGroup.SubjectId)] = subject.Id;
|
||||
changed = true;
|
||||
}
|
||||
else if (!hasSubjectId && group.ContainsKey(nameof(LearningGroup.SubjectId)))
|
||||
{
|
||||
group[nameof(LearningGroup.SubjectId)] = BsonValue.Null;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
changed |= group.Remove("Subject");
|
||||
if (changed) groups.Update(group);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateMemberships()
|
||||
{
|
||||
const string oldName = "enrollments";
|
||||
const string newName = "group_memberships";
|
||||
var names = _db.GetCollectionNames().ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
if (names.Contains(oldName) && !names.Contains(newName))
|
||||
_db.RenameCollection(oldName, newName);
|
||||
|
||||
var memberships = _db.GetCollection<BsonDocument>(newName);
|
||||
foreach (var membership in memberships.FindAll().ToList())
|
||||
{
|
||||
var changed = false;
|
||||
if (!membership.ContainsKey(nameof(GroupMembership.AddedOn)) &&
|
||||
membership.TryGetValue("EnrolledAt", out var enrolledAt))
|
||||
{
|
||||
membership[nameof(GroupMembership.AddedOn)] = enrolledAt;
|
||||
changed = true;
|
||||
}
|
||||
changed |= membership.Remove("EnrolledAt");
|
||||
changed |= membership.Remove("SchoolYear");
|
||||
if (changed) memberships.Update(membership);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveRedundantLegacyFields()
|
||||
{
|
||||
RemoveFields("exams", "Subject");
|
||||
RemoveFields("units", "Subject", "SchoolYear");
|
||||
RemoveFields("grades", "SchoolYear");
|
||||
RemoveFields("participation", "GroupId", "Date");
|
||||
}
|
||||
|
||||
private void RemoveFields(string collectionName, params string[] fieldNames)
|
||||
{
|
||||
var collection = _db.GetCollection<BsonDocument>(collectionName);
|
||||
foreach (var document in collection.FindAll().ToList())
|
||||
{
|
||||
var changed = false;
|
||||
foreach (var fieldName in fieldNames) changed |= document.Remove(fieldName);
|
||||
if (changed) collection.Update(document);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureIndexes()
|
||||
@@ -59,13 +140,16 @@ public class LiteDbContext : IDisposable
|
||||
Students.EnsureIndex(x => x.IsActive);
|
||||
Groups.EnsureIndex(x => x.SchoolYear);
|
||||
Groups.EnsureIndex(x => x.IsActive);
|
||||
Enrollments.EnsureIndex(x => x.StudentId);
|
||||
Enrollments.EnsureIndex(x => x.GroupId);
|
||||
Enrollments.EnsureIndex(x => x.SchoolYear);
|
||||
Memberships.EnsureIndex(x => x.StudentId);
|
||||
Memberships.EnsureIndex(x => x.GroupId);
|
||||
Memberships.EnsureIndex("ux_student_group",
|
||||
BsonExpression.Create("STRING($.StudentId) + ':' + STRING($.GroupId)"), unique: true);
|
||||
Exams.EnsureIndex(x => x.GroupId);
|
||||
Exams.EnsureIndex(x => x.Status);
|
||||
ExamResults.EnsureIndex(x => x.ExamId);
|
||||
ExamResults.EnsureIndex(x => x.StudentId);
|
||||
ExamResults.EnsureIndex("ux_exam_student",
|
||||
BsonExpression.Create("STRING($.ExamId) + ':' + STRING($.StudentId)"), unique: true);
|
||||
Grades.EnsureIndex(x => x.StudentId);
|
||||
Grades.EnsureIndex(x => x.GroupId);
|
||||
GradingKeyTemplates.EnsureIndex(x => x.GradingSystem);
|
||||
@@ -80,8 +164,11 @@ public class LiteDbContext : IDisposable
|
||||
ParticipationSessions.EnsureIndex(x => x.Date);
|
||||
ParticipationEntries.EnsureIndex(x => x.SessionId);
|
||||
ParticipationEntries.EnsureIndex(x => x.StudentId);
|
||||
ParticipationEntries.EnsureIndex("ux_session_student",
|
||||
BsonExpression.Create("STRING($.SessionId) + ':' + STRING($.StudentId)"), unique: true);
|
||||
ParticipationAspects.EnsureIndex(x => x.GroupId);
|
||||
Subjects.EnsureIndex(x => x.Name);
|
||||
Subjects.EnsureIndex("ux_subject_name", BsonExpression.Create("LOWER(TRIM($.Name))"), unique: true);
|
||||
CompetencyDomains.EnsureIndex(x => x.SubjectId);
|
||||
CompetencyDomains.EnsureIndex(x => x.GradeLevel);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ public class StudentRepository(LiteDbContext db) : IStudentRepository
|
||||
public List<Student> GetAll(bool includeInactive = false) =>
|
||||
(includeInactive ? db.Students.FindAll() : db.Students.Find(s => s.IsActive))
|
||||
.OrderBy(s => s.LastName).ToList();
|
||||
public List<Student> GetByGroup(Guid groupId, string schoolYear)
|
||||
public List<Student> GetByGroup(Guid groupId)
|
||||
{
|
||||
var ids = db.Enrollments
|
||||
.Find(e => e.GroupId == groupId && e.SchoolYear == schoolYear)
|
||||
var ids = db.Memberships
|
||||
.Find(e => e.GroupId == groupId)
|
||||
.Select(e => e.StudentId).ToHashSet();
|
||||
return db.Students.Find(s => ids.Contains(s.Id)).OrderBy(s => s.LastName).ToList();
|
||||
}
|
||||
@@ -31,11 +31,17 @@ public class GroupRepository(LiteDbContext db) : IGroupRepository
|
||||
? db.Groups.Find(g => g.SchoolYear == schoolYear)
|
||||
: db.Groups.Find(g => g.SchoolYear == schoolYear && g.IsActive))
|
||||
.OrderBy(g => g.Name).ToList();
|
||||
public void Save(LearningGroup g) { g.UpdatedAt = DateTime.UtcNow; db.Groups.Upsert(g); }
|
||||
public void Save(LearningGroup g)
|
||||
{
|
||||
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;
|
||||
db.Groups.Upsert(g);
|
||||
}
|
||||
public void Delete(Guid id)
|
||||
{
|
||||
foreach (var enrollment in db.Enrollments.Find(e => e.GroupId == id).ToList())
|
||||
db.Enrollments.Delete(enrollment.Id);
|
||||
foreach (var membership in db.Memberships.Find(e => e.GroupId == id).ToList())
|
||||
db.Memberships.Delete(membership.Id);
|
||||
|
||||
foreach (var exam in db.Exams.Find(e => e.GroupId == id).ToList())
|
||||
{
|
||||
@@ -71,16 +77,22 @@ public class GroupRepository(LiteDbContext db) : IGroupRepository
|
||||
}
|
||||
}
|
||||
|
||||
public class EnrollmentRepository(LiteDbContext db) : IEnrollmentRepository
|
||||
public class GroupMembershipRepository(LiteDbContext db) : IGroupMembershipRepository
|
||||
{
|
||||
public List<Enrollment> GetByStudent(Guid id) =>
|
||||
db.Enrollments.Find(e => e.StudentId == id).ToList();
|
||||
public List<Enrollment> GetByGroup(Guid id) =>
|
||||
db.Enrollments.Find(e => e.GroupId == id).ToList();
|
||||
public List<Enrollment> GetByGroupAndYear(Guid groupId, string sy) =>
|
||||
db.Enrollments.Find(e => e.GroupId == groupId && e.SchoolYear == sy).ToList();
|
||||
public void Save(Enrollment e) => db.Enrollments.Upsert(e);
|
||||
public void Delete(Guid id) => db.Enrollments.Delete(id);
|
||||
public List<GroupMembership> GetByStudent(Guid id) =>
|
||||
db.Memberships.Find(e => e.StudentId == id).ToList();
|
||||
public List<GroupMembership> GetByGroup(Guid id) =>
|
||||
db.Memberships.Find(e => e.GroupId == id).ToList();
|
||||
public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
||||
db.Memberships.FindOne(e => e.StudentId == studentId && e.GroupId == groupId);
|
||||
public void Save(GroupMembership membership)
|
||||
{
|
||||
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 class ExamRepository(LiteDbContext db) : IExamRepository
|
||||
@@ -240,10 +252,25 @@ public class SubjectRepository(LiteDbContext db) : ISubjectRepository
|
||||
{
|
||||
public List<Subject> GetAll() => db.Subjects.FindAll().OrderBy(s => s.Name).ToList();
|
||||
public Subject? GetById(Guid id) => db.Subjects.FindById(id);
|
||||
public Subject? GetByName(string name) =>
|
||||
db.Subjects.FindOne(s => s.Name == name);
|
||||
public void Save(Subject s) { s.UpdatedAt = DateTime.UtcNow; db.Subjects.Upsert(s); }
|
||||
public void Delete(Guid id) => db.Subjects.Delete(id);
|
||||
public Subject? GetByName(string name) => db.Subjects.FindAll().FirstOrDefault(s =>
|
||||
string.Equals(s.Name.Trim(), name.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
public void Save(Subject s)
|
||||
{
|
||||
s.Name = s.Name.Trim();
|
||||
s.ShortName = s.ShortName.Trim();
|
||||
if (s.Name.Length == 0) throw new ArgumentException("Der Fachname darf nicht leer sein.");
|
||||
var duplicate = GetByName(s.Name);
|
||||
if (duplicate is not null && duplicate.Id != s.Id)
|
||||
throw new InvalidOperationException("Ein Fach mit diesem Namen existiert bereits.");
|
||||
s.UpdatedAt = DateTime.UtcNow;
|
||||
db.Subjects.Upsert(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);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompetencyDomainRepository(LiteDbContext db) : ICompetencyDomainRepository
|
||||
|
||||
Reference in New Issue
Block a user