Skip to content

Audit & Soft delete

Interceptor central

Application/Library/Interceptors/AuditableAndSoftDeleteInterceptor.cs est branché sur ApplicationDbContext dans Startup.cs > AddInterceptors.

Il fait deux choses au moment de SaveChanges :

1. Soft delete

Pour toute entité implémentant ISoftDelete qui passe en EntityState.Deleted :

  • Le state est forcé à EntityState.Modified.
  • IsDeleted = true est posé.
  • DeletedAt / DeletedBy (si présents) sont remplis.

Conséquence : les entités ne sont jamais physiquement supprimées (sauf IgnoreQueryFilters() + RemoveRange).

2. Audit (timestamps + user)

Pour toute entité implémentant ITimeStamped ou IAuditableEntity :

  • À Added : CreatedAt = DateTime.Now, CreatedBy = <user> (résolu via IHttpContextAccessor).
  • À Modified : UpdatedAt, UpdatedBy.

Filtre global EF

ApplicationDbContext.OnModelCreating configure (à confirmer) un global query filter pour exclure IsDeleted = true automatiquement sur les entités ISoftDelete.

Conséquence : tous les _db.Bookings.Where(...) ignorent silencieusement les soft-deleted. Pour les inclure :

csharp
_db.Bookings.IgnoreQueryFilters().Where(...)

Hiérarchie des classes de base

BaseEntity
  ├─ BaseTimeStampedEntity (CreatedAt, UpdatedAt — ITimeStamped)
  └─ BaseAuditableEntity   (+ CreatedBy, UpdatedBy — IAuditableEntity)

Les entités métier choisissent ce dont elles ont besoin et implémentent ISoftDelete quand pertinent.

AuditEntity (journal séparé)

Une entité AuditEntity stocke un journal d'audit séparé pour les changements importants. Géré par AuditEntityService et exposé dans Pages/AuditEntities/. À ne pas confondre avec BaseAuditableEntity qui ne fait que poser CreatedBy/UpdatedBy.

Pièges courants

  1. Soft delete cascade : EF ne fait PAS de cascade soft-delete sur les enfants. Si on supprime un parent, les enfants restent en base avec IsDeleted = false mais le parent est masqué — donc orphelins potentiellement visibles si l'enfant est requêté indépendamment. À vérifier au cas par cas.
  2. Sort + filter : un OrderBy(x => x.Children.Count()) peut renvoyer un compte qui inclut les soft-deleted enfants (ou pas, selon la version EF). Toujours tester.
  3. Perf : le filter ajoute WHERE IsDeleted = 0 à toutes les queries. Indexer sur IsDeleted ou sur des composites (IsDeleted, FK) si nécessaire.

Remplacements directs (hard delete)

Cas autorisés :

  • Purge admin (compte guest sans booking, cf. CleanGuestCustomers).
  • Tests : on hard-delete pour repartir propre.

⚠ Toute hard-delete doit être explicite et justifiée (commentaire dans le code).

Contributors

No contributors

Changelog

No recent changes