/// <summary> /// Save audit entities where the value of some properties were unknown at previous step. /// <br/><br/> /// https://www.meziantou.net/entity-framework-core-history-audit-table.htm /// </summary> /// <method>OnAfterSaveChangesAsync(List<AuditEntry> auditEntries)</method> private Task OnAfterSaveChangesAsync(List <AuditEntry> auditEntries) { if (auditEntries == null || auditEntries.Count == 0) { return(Task.CompletedTask); } foreach (var auditEntry in auditEntries) { // Get the final value of the temporary properties foreach (var prop in auditEntry.TemporaryProperties) { if (prop.Metadata.IsPrimaryKey()) { auditEntry.KeyValues[prop.Metadata.Name] = prop.CurrentValue; } else { auditEntry.CurrentValues[prop.Metadata.Name] = prop.CurrentValue; } } // Save the Audit entry AuditHistory.Add(auditEntry.ToAuditHistory()); } return(SaveChangesAsync()); }
/// <summary> /// Audit History record to write /// </summary> /// <method>ToAuditHistory()</method> public AuditHistory ToAuditHistory() { string file = this.GetType().Assembly.Location; string app = System.IO.Path.GetFileNameWithoutExtension(file); var auditHistory = new AuditHistory(); auditHistory.Entity = TableName; auditHistory.State = State; auditHistory.Application = app; auditHistory.ModifiedBy = ModifiedBy; auditHistory.ModifiedOn = ModifiedOn; auditHistory.KeyValues = JsonConvert.SerializeObject(KeyValues); auditHistory.OriginalValues = OriginalValues.Count == 0 ? null : JsonConvert.SerializeObject(OriginalValues); auditHistory.CurrentValues = CurrentValues.Count == 0 ? null : JsonConvert.SerializeObject(CurrentValues); return(auditHistory); }
/// <summary> /// Save audit entities that have all the modifications and return list of entries /// where the value of some properties are unknown at this step. /// <br/><br/> /// https://www.meziantou.net/entity-framework-core-history-audit-table.htm /// </summary> /// <returns>List<AuditEntry></returns> /// <method>OnBeforeSaveChanges(string userId)</method> private List <AuditEntry> OnBeforeSaveChanges(string userId) { ChangeTracker.DetectChanges(); var auditEntries = new List <AuditEntry>(); foreach (var entry in ChangeTracker.Entries()) { if (entry.Entity is AuditHistory || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged) { continue; } var auditEntry = new AuditEntry(entry); auditEntry.TableName = entry.Metadata.GetTableName(); auditEntry.ModifiedBy = userId; auditEntry.ModifiedOn = DateTime.UtcNow; auditEntry.State = entry.State.ToString(); auditEntries.Add(auditEntry); foreach (var property in entry.Properties) { if (property.IsTemporary) { // value will be generated by the database, get the value after saving auditEntry.TemporaryProperties.Add(property); continue; } string propertyName = property.Metadata.Name; if (property.Metadata.IsPrimaryKey()) { auditEntry.KeyValues[propertyName] = property.CurrentValue; continue; } switch (entry.State) { case EntityState.Added: auditEntry.CurrentValues[propertyName] = property.CurrentValue; break; case EntityState.Deleted: auditEntry.OriginalValues[propertyName] = property.OriginalValue; break; case EntityState.Modified: if (property.IsModified) { auditEntry.OriginalValues[propertyName] = property.OriginalValue; auditEntry.CurrentValues[propertyName] = property.CurrentValue; } break; } } } // Save audit entities that have all the modifications foreach (var auditEntry in auditEntries.Where(_ => !_.HasTemporaryProperties)) { AuditHistory.Add(auditEntry.ToAuditHistory()); } // keep a list of entries where the value of some properties are unknown at this step return(auditEntries.Where(_ => _.HasTemporaryProperties).ToList()); }