fix db model

This commit is contained in:
beo3000 2025-12-21 12:03:46 +01:00
parent d653225c5f
commit 3024ed85d2
12 changed files with 67 additions and 26 deletions

View File

@ -30,6 +30,11 @@ public class PersonExpense : BaseEntity
/// </summary>
public Guid? GameId { get; set; } // Foreign Key
/// <summary>
/// Id of a club.
/// </summary>
public Guid ClubId { get; set; }
// Stammdaten
/// <summary>
@ -57,11 +62,6 @@ public class PersonExpense : BaseEntity
// Navigation Properties
/// <summary>
/// Id of a club.
/// </summary>
public Guid ClubId { get; set; }
/// <summary>
/// ID des Benutzers, der die Zuordnung vorgenommen hat.
/// </summary>

View File

@ -42,4 +42,33 @@ public class AppDbContext : DbContext
// Deine IEntityTypeConfiguration<> Klassen automatisch anwenden
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
public override int SaveChanges()
{
ConvertDeletesToSoftDeletes();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
ConvertDeletesToSoftDeletes();
return base.SaveChangesAsync(cancellationToken);
}
private void ConvertDeletesToSoftDeletes()
{
foreach (var entry in ChangeTracker.Entries<BaseEntity>())
{
if (entry.State == EntityState.Deleted)
{
entry.State = EntityState.Modified;
entry.Entity.IsDeleted = true;
entry.Entity.ModifiedAt = DateTime.UtcNow;
}
}
}
}

View File

@ -21,6 +21,8 @@ public class ClubConfiguration : IEntityTypeConfiguration<Club>
.HasConversion<int>()
.IsRequired();
builder.HasIndex(x => x.Name);
builder.HasQueryFilter(x => !x.IsDeleted);
}
}

View File

@ -32,14 +32,14 @@ public class DayPersonConfiguration : IEntityTypeConfiguration<DayPerson>
.WithMany(x => x.DayPersons)
.HasForeignKey(x => new { x.DayId, x.ClubId })
.HasPrincipalKey(d => new { d.Id, d.ClubId })
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
// Club-Konsistenz: (PersonId, ClubId) muss in Person(Id, ClubId) existieren
builder.HasOne(x => x.Person)
.WithMany(x => x.DayPersons)
.HasForeignKey(x => new { x.PersonId, x.ClubId })
.HasPrincipalKey(p => new { p.Id, p.ClubId })
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
@ -58,10 +58,6 @@ public class DayPersonConfiguration : IEntityTypeConfiguration<DayPerson>
builder.HasIndex(x => x.ClubId);
builder.HasIndex(x => x.DayId);
builder.HasIndex(x => x.PersonId);
}
}

View File

@ -42,12 +42,13 @@ public class ExpenseConfiguration : IEntityTypeConfiguration<Expense>
builder.HasOne(x => x.Club)
.WithMany()
.HasForeignKey(x => x.ClubId)
.OnDelete(DeleteBehavior.Restrict);
.OnDelete(DeleteBehavior.NoAction);
// Alternate Key für Composite-FK in ExpenseTrigger: (Id, ClubId)
builder.HasAlternateKey(x => new { x.Id, x.ClubId });
builder.HasIndex(x => x.ClubId);
builder.HasIndex(x => new { x.ClubId, x.Name });
builder.HasQueryFilter(x => !x.IsDeleted);

View File

@ -38,12 +38,12 @@ public class ExpenseTriggerConfiguration : IEntityTypeConfiguration<ExpenseTrigg
.WithMany()
.HasForeignKey(x => new { x.ExpenseId, x.ClubId })
.HasPrincipalKey(e => new { e.Id, e.ClubId })
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Trigger)
.WithMany()
.HasForeignKey(x => x.TriggerId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasIndex(x => x.ExpenseId);
builder.HasIndex(x => x.TriggerId);

View File

@ -39,7 +39,7 @@ public class GameConfiguration : IEntityTypeConfiguration<Game>
builder.HasOne(x => x.Day)
.WithMany()
.HasForeignKey(x => x.DayId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
// Mehrere Games pro Day -> Index nicht unique
builder.HasIndex(x => x.DayId);

View File

@ -20,14 +20,16 @@ public class GamePersonConfiguration : IEntityTypeConfiguration<GamePerson>
builder.HasOne(x => x.Game)
.WithMany(x => x.GamePersons)
.HasForeignKey(x => x.GameId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PersonId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasIndex(x => x.PersonId);
builder.HasIndex(x => x.GameId);
// ✅ Matching Query Filter:

View File

@ -36,7 +36,7 @@ public class PersonConfiguration : IEntityTypeConfiguration<Person>
builder.HasMany(x => x.Expenses)
.WithOne(x => x.Person)
.HasForeignKey(x => x.PersonId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasIndex(x => x.ClubId);

View File

@ -39,40 +39,49 @@ public class PersonExpenseConfiguration : IEntityTypeConfiguration<PersonExpense
builder.Property(x => x.AssignedById).IsRequired();
// Soft-delete only => DB soll nicht cascade-löschen
builder.HasOne(x => x.Person)
.WithMany(x => x.Expenses)
.HasForeignKey(x => x.PersonId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Day)
.WithMany()
.HasForeignKey(x => x.DayId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Expense)
.WithMany()
.HasForeignKey(x => x.ExpenseId)
.OnDelete(DeleteBehavior.Restrict);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Game)
.WithMany()
.HasForeignKey(x => x.GameId)
.OnDelete(DeleteBehavior.SetNull);
// SQL Server: verhindert multiple cascade paths (SET NULL ist eine kaskadierende Aktion)
.OnDelete(DeleteBehavior.NoAction);
builder.HasIndex(x => x.ClubId);
builder.HasIndex(x => new { x.PersonId, x.DayId });
builder.HasIndex(x => x.DayId);
builder.HasIndex(x => x.GameId);
builder.HasQueryFilter(pe =>
// required Principals müssen sichtbar sein
!pe.IsDeleted &&
!pe.Club.IsDeleted &&
!pe.Person.IsDeleted &&
!pe.Day.IsDeleted &&
!pe.Expense.IsDeleted &&
// optionales Game: entweder kein Game, oder Game + dessen Day sichtbar
(pe.GameId == null || (!pe.Game!.IsDeleted && !pe.Game!.Day.IsDeleted))
);
}
}

View File

@ -26,6 +26,8 @@ public class TriggerConfiguration : IEntityTypeConfiguration<Trigger>
.HasConversion<int>()
.IsRequired();
builder.HasIndex(x => x.ExpenseTriggerType);
builder.HasQueryFilter(x => !x.IsDeleted);
}
}

View File

@ -20,12 +20,12 @@ public class UserProfileClubConfiguration : IEntityTypeConfiguration<UserProfile
builder.HasOne(x => x.UserProfile)
.WithMany(x => x.Clubs)
.HasForeignKey(x => x.UserProfileId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Club)
.WithMany()
.HasForeignKey(x => x.ClubId)
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.NoAction);
builder.Property(x => x.IsDefault).IsRequired();