fix db model
This commit is contained in:
parent
d653225c5f
commit
3024ed85d2
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ public class ClubConfiguration : IEntityTypeConfiguration<Club>
|
|||
.HasConversion<int>()
|
||||
.IsRequired();
|
||||
|
||||
builder.HasIndex(x => x.Name);
|
||||
|
||||
builder.HasQueryFilter(x => !x.IsDeleted);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public class TriggerConfiguration : IEntityTypeConfiguration<Trigger>
|
|||
.HasConversion<int>()
|
||||
.IsRequired();
|
||||
|
||||
builder.HasIndex(x => x.ExpenseTriggerType);
|
||||
|
||||
builder.HasQueryFilter(x => !x.IsDeleted);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue