/// <summary> /// Discards the prepared audit records. This method should be called /// when the actual changes could not be saved to the database. /// </summary> /// <param name="context"> /// The database context whose changes were recorded. /// </param> /// <param name="cancellationToken"> /// A token to monitor for cancellation requests. /// </param> /// <returns>A task that represents the asynchronous operation.</returns> public static async Task DiscardRecordedChangesAsync(this IAuditedContext context, CancellationToken cancellationToken = default) { if (!context.CanAudit()) { return; } await Task.WhenAll(context.ChangeRecorders.Select(x => x.DiscardAsync(cancellationToken))); }
private static void RecordChange(this IAuditedContext context, EntityEntry entity, IAuditedEntity auditedEntity) { if (!context.CanAudit()) { return; } switch (entity.State) { case EntityState.Added: foreach (var changeRecorder in context.ChangeRecorders) { changeRecorder.RecordAdd(auditedEntity); } break; case EntityState.Deleted: foreach (var changeRecorder in context.ChangeRecorders) { changeRecorder.RecordDelete(auditedEntity); } break; case EntityState.Modified: foreach (var property in entity.CurrentValues.Properties) { var entry = entity.Property(property.Name); // Note: do not change the line below into `!=`! // `Equals(object, object)` calls an overridden Equals, // whereas `object != object` does not. if (entry.IsModified && !Equals(entry.CurrentValue, entry.OriginalValue)) { foreach (var changeRecorder in context.ChangeRecorders) { changeRecorder.RecordChange(auditedEntity, property.Name, entry.OriginalValue, entry.CurrentValue); } } } break; } }
/// <summary> /// Records the currently tracked changes in the database context to all /// change recorders. /// </summary> /// <param name="context"> /// The database context that contains the changes. /// </param> public static void RecordChanges(this IAuditedContext context) { if (context.ChangeTracker.AutoDetectChangesEnabled) { context.ChangeTracker.DetectChanges(); } foreach (var entity in context.ChangeTracker.Entries().Where(e => e.Entity is IAuditedEntity)) { var auditedEntity = (IAuditedEntity)entity.Entity; switch (entity.State) { case EntityState.Added: auditedEntity.Created = DateTimeOffset.Now; auditedEntity.CreatedBy = context.Identity?.Id; break; case EntityState.Modified: auditedEntity.LastModified = DateTimeOffset.Now; auditedEntity.LastModifiedBy = context.Identity?.Id; break; } context.RecordChange(entity, auditedEntity); } if (context.CanAudit()) { foreach (var changeRecorder in context.ChangeRecorders) { if (changeRecorder is IHasParentContext parentContextRecorder) { parentContextRecorder.ParentContext = (IAuditContext)context; } changeRecorder.OnSavingChanges(); } } }