public static void AuditEntityAdded(Audit audit, EntityEntry objectStateEntry) #endif { var entry = new AuditEntry(audit, objectStateEntry) { State = AuditEntryState.EntityAdded }; // CHECK if the key should be resolved in POST Action #if EF5 || EF6 if (objectStateEntry.EntityKey.IsTemporary) { entry.DelayedKey = objectStateEntry; } AuditEntityAdded(entry, objectStateEntry.CurrentValues); #elif EF7 // TODO: We must check if the key IsTemporary! We can maybe use flag... //if (!objectStateEntry.IsKeySet) //{ entry.DelayedKey = objectStateEntry; //} AuditEntityAdded(entry, objectStateEntry); #endif audit.Entries.Add(entry); }
public static Audit AutoSaveAudit() { var audit = new Audit(); audit.CreatedBy = "ZZZ Projects"; audit.Configuration.AutoSavePreAction = (context, audit1) => (context as TestContext).AuditEntries.AddRange(audit1.Entries); return audit; }
/// <summary>Pre save changes.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="context">The context used to audits and saves all changes made.</param> public static void PreSaveChanges(Audit audit, DbContext context) { #if EF5 || EF6 var objectContext = context.GetObjectContext(); objectContext.DetectChanges(); var changes = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted); foreach (var objectStateEntry in changes) { if (objectStateEntry.IsRelationship) { if (objectStateEntry.State == EntityState.Added && audit.Configuration.IncludeRelationAdded) { AuditRelationAdded(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Deleted && audit.Configuration.IncludeRelationDeleted) { AuditRelationDeleted(audit, objectStateEntry); } } else { if (objectStateEntry.State == EntityState.Added && audit.Configuration.IncludeEntityAdded) { AuditEntityAdded(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Deleted && audit.Configuration.IncludeEntityDeleted) { AuditEntityDeleted(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Modified && audit.Configuration.IncludeEntityModified) { AuditEntityModified(audit, objectStateEntry); } } } #elif EF7 context.ChangeTracker.DetectChanges(); var manager = context.ChangeTracker.GetStateManager(); var entries = manager.Entries; foreach (var entry in entries) { if (entry.EntityState == EntityState.Added) { } else if (entry.EntityState == EntityState.Deleted) { } else if (entry.EntityState == EntityState.Modified) { } } #endif }
public static Audit AutoSaveAudit() { var audit = new Audit(); #if EF5 || EF6 audit.Configuration.AutoSavePreAction = (context, audit1) => (context as TestContext).AuditEntries.AddRange(audit1.Entries); #endif return audit; }
/// <summary>Audit entity deleted.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> public static void AuditEntityDeleted(Audit audit, ObjectStateEntry objectStateEntry) { var entry = new AuditEntry(objectStateEntry) { State = AuditEntryState.EntityDeleted }; AuditEntityDeleted(entry, objectStateEntry.OriginalValues); audit.Entries.Add(entry); }
/// <summary>Audits and saves all changes made in this context to the underlying database.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <returns>The number of objects written to the underlying database.</returns> public static int SaveChanges(this DbContext context, Audit audit) { AuditStateEntry.PreSaveChanges(audit, context); var result = context.SaveChanges(); AuditStateEntry.PostSaveChanges(audit); if (audit.Configuration.AutoSaveAction != null) { audit.Configuration.AutoSaveAction(context, audit); context.SaveChanges(); } return result; }
/// <summary>Audits and saves all changes made in this context to the underlying database.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <returns>The number of objects written to the underlying database.</returns> public static int SaveChanges(this DbContext context, Audit audit) { audit.PreSaveChanges(context); var rowAffecteds = context.SaveChanges(); audit.PostSaveChanges(); if (audit.CurrentOrDefaultConfiguration.AutoSavePreAction != null) { audit.CurrentOrDefaultConfiguration.AutoSavePreAction(context, audit); context.SaveChanges(); } return rowAffecteds; }
/// <summary>A DbContext extension method that saves the changes asynchronous.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="cancellationToken">A CancellationToken to observe while waiting for the task to complete.</param> /// <returns> /// A task that represents the asynchronous save operation. The task result contains the number of objects written /// to the underlying database /// </returns> public static async Task<int> SaveChangesAsync(this DbContext context, Audit audit, CancellationToken cancellationToken) { audit.PreSaveChanges(context); var rowAffecteds = await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); audit.PostSaveChanges(); if (audit.CurrentOrDefaultConfiguration.AutoSavePreAction != null) { audit.CurrentOrDefaultConfiguration.AutoSavePreAction(context, audit); await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } return rowAffecteds; }
/// <summary>Audit entity added.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> public static void AuditEntityAdded(Audit audit, ObjectStateEntry objectStateEntry) { var entry = new AuditEntry(objectStateEntry) { State = AuditEntryState.EntityAdded }; // CHECK if the key should be resolved in POST Action if (objectStateEntry.EntityKey.IsTemporary) { entry.DelayedKey = objectStateEntry; } AuditEntityAdded(entry, objectStateEntry.CurrentValues); audit.Entries.Add(entry); }
public static void AuditEntityDeleted(Audit audit, EntityEntry objectStateEntry) #endif { var entry = new AuditEntry(audit, objectStateEntry) { State = AuditEntryState.EntityDeleted }; #if EF5 || EF6 AuditEntityDeleted(entry, objectStateEntry.OriginalValues); #elif EFCORE AuditEntityDeleted(entry, objectStateEntry); #endif audit.Entries.Add(entry); }
/// <summary>A DbContext extension method that saves the changes asynchronous.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="cancellationToken">A CancellationToken to observe while waiting for the task to complete.</param> /// <returns> /// A task that represents the asynchronous save operation. The task result contains the number of objects written /// to the underlying database /// </returns> public static Task<int> SaveChangesAsync(this DbContext context, Audit audit, CancellationToken cancellationToken) { AuditStateEntry.PreSaveChanges(audit, context); var result = context.SaveChangesAsync(cancellationToken); AuditStateEntry.PostSaveChanges(audit); if (audit.Configuration.AutoSaveAsyncAction != null) { result.ContinueWith(x => { audit.Configuration.AutoSaveAsyncAction(context, audit, cancellationToken); return x.Result; }, cancellationToken).ConfigureAwait(false); } return result; }
/// <summary>Audit entity modified.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> public static void AuditEntityModified(Audit audit, ObjectStateEntry objectStateEntry) { var entry = new AuditEntry(objectStateEntry) { State = AuditEntryState.EntityModified }; if (audit.Configuration.IsSoftAdded != null && audit.Configuration.IsSoftAdded(objectStateEntry.Entity)) { entry.State = AuditEntryState.EntitySoftAdded; } else if (audit.Configuration.IsSoftDeleted != null && audit.Configuration.IsSoftDeleted(objectStateEntry.Entity)) { entry.State = AuditEntryState.EntitySoftDeleted; } AuditEntityModified(audit, entry, objectStateEntry.OriginalValues, objectStateEntry.CurrentValues); audit.Entries.Add(entry); }
/// <summary>Posts a save changes.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> public static void PostSaveChanges(Audit audit) { foreach (var entry in audit.Entries) { if (entry.DelayedKey != null) { var objectStateEntry = entry.DelayedKey as ObjectStateEntry; if (objectStateEntry != null) { if (objectStateEntry.IsRelationship) { var values = objectStateEntry.CurrentValues; var value_0 = (EntityKey) values.GetValue(0); var value_1 = (EntityKey) values.GetValue(1); var relationName_0 = values.GetName(0); var relationName_1 = values.GetName(1); foreach (var keyValue in value_0.EntityKeyValues) { var keyName = string.Concat(relationName_0, ";", keyValue.Key); entry.Properties.Add(new AuditEntryProperty(keyName, null, keyValue.Value)); } foreach (var keyValue in value_1.EntityKeyValues) { var keyName = string.Concat(relationName_1, ";", keyValue.Key); entry.Properties.Add(new AuditEntryProperty(keyName, null, keyValue.Value)); } } else { foreach (var keyValue in objectStateEntry.EntityKey.EntityKeyValues) { var property = entry.Properties.First(x => x.PropertyName == keyValue.Key); property.NewValue = keyValue.Value; } } } } } }
public static void AuditRelationDeleted(Audit audit, EntityEntry objectStateEntry) #endif { var entry = new AuditEntry(audit, objectStateEntry) { State = AuditEntryState.RelationshipDeleted }; var values = objectStateEntry.OriginalValues; for (var i = 0; i < values.FieldCount; i++) { var relationName = values.GetName(i); var value = (EntityKey) values.GetValue(i); foreach (var keyValue in value.EntityKeyValues) { entry.Properties.Add(new AuditEntryProperty(entry, relationName, keyValue.Key, keyValue.Value, null)); } } audit.Entries.Add(entry); }
/// <summary>Audit relationship deleted.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> public static void AuditRelationDeleted(Audit audit, ObjectStateEntry objectStateEntry) { var entry = new AuditEntry(objectStateEntry) { State = AuditEntryState.RelationshipDeleted }; var values = objectStateEntry.OriginalValues; for (var i = 0; i < values.FieldCount; i++) { var relationName = values.GetName(i); var value = (EntityKey) values.GetValue(i); foreach (var keyValue in value.EntityKeyValues) { // todo: better add a new property association? var keyName = string.Concat(relationName, ";", keyValue.Key); entry.Properties.Add(new AuditEntryProperty(keyName, keyValue.Value, null)); } } audit.Entries.Add(entry); }
public static void AuditEntityModified(Audit audit, AuditEntry entry, DbDataRecord orginalRecord, DbUpdatableDataRecord currentRecord, string prefix = "") { for (var i = 0; i < orginalRecord.FieldCount; i++) { var name = orginalRecord.GetName(i); var originalValue = orginalRecord.GetValue(i); var currentValue = currentRecord.GetValue(i); var valueRecord = originalValue as DbDataRecord; if (valueRecord != null) { // Complex Type AuditEntityModified(audit, entry, valueRecord, currentValue as DbUpdatableDataRecord, string.Concat(prefix, name, ".")); } else { if (audit.Configuration.IncludePropertyUnchanged || !Equals(currentValue, originalValue)) { entry.Properties.Add(new AuditEntryProperty(string.Concat(prefix, name), originalValue, currentValue)); } } } }
/// <summary>Audit relationship added.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> public static void AuditRelationAdded(Audit audit, ObjectStateEntry objectStateEntry) { var entry = new AuditEntry(objectStateEntry) { State = AuditEntryState.RelationshipAdded }; var values = objectStateEntry.CurrentValues; var value_0 = (EntityKey) values.GetValue(0); var value_1 = (EntityKey) values.GetValue(1); if (value_0.IsTemporary || value_1.IsTemporary) { entry.DelayedKey = objectStateEntry; } else { var relationName_0 = values.GetName(0); var relationName_1 = values.GetName(1); foreach (var keyValue in value_0.EntityKeyValues) { var keyName = string.Concat(relationName_0, ";", keyValue.Key); entry.Properties.Add(new AuditEntryProperty(keyName, null, keyValue.Value)); } foreach (var keyValue in value_1.EntityKeyValues) { var keyName = string.Concat(relationName_1, ";", keyValue.Key); entry.Properties.Add(new AuditEntryProperty(keyName, null, keyValue.Value)); } } audit.Entries.Add(entry); }
public static void AuditRelationAdded(Audit audit, EntityEntry objectStateEntry) #endif { var entry = new AuditEntry(audit, objectStateEntry) { State = AuditEntryState.RelationshipAdded }; var values = objectStateEntry.CurrentValues; var leftKeys = (EntityKey) values.GetValue(0); var rightKeys = (EntityKey) values.GetValue(1); if (leftKeys.IsTemporary || rightKeys.IsTemporary) { entry.DelayedKey = objectStateEntry; } else { var leftRelationName = values.GetName(0); var rightRelationName = values.GetName(1); foreach (var keyValue in leftKeys.EntityKeyValues) { entry.Properties.Add(new AuditEntryProperty(entry, leftRelationName, keyValue.Key, null, keyValue.Value)); } foreach (var keyValue in rightKeys.EntityKeyValues) { entry.Properties.Add(new AuditEntryProperty(entry, rightRelationName, keyValue.Key, null, keyValue.Value)); } } audit.Entries.Add(entry); }
/// <summary>Pre save changes.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="context">The context used to audits and saves all changes made.</param> public static void PreSaveChanges(Audit audit, DbContext context) { var objectContext = context.GetObjectContext(); objectContext.DetectChanges(); var changes = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted); foreach (var objectStateEntry in changes) { if (objectStateEntry.IsRelationship) { if (objectStateEntry.State == EntityState.Added && audit.Configuration.IncludeRelationshipAdded) { AuditRelationAdded(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Deleted && audit.Configuration.IncludeRelationshipDeleted) { AuditRelationDeleted(audit, objectStateEntry); } } else { if (objectStateEntry.State == EntityState.Added && audit.Configuration.IncludeEntityAdded) { AuditEntityAdded(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Deleted && audit.Configuration.IncludeEntityDeleted) { AuditEntityDeleted(audit, objectStateEntry); } else if (objectStateEntry.State == EntityState.Modified && audit.Configuration.IncludeEntityModified) { AuditEntityModified(audit, objectStateEntry); } } } }
/// <summary>Updates audit entries after the save changes has been executed.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> public static void PostSaveChanges(Audit audit) { foreach (var entry in audit.Entries) { if (entry.DelayedKey != null) { #if EF5 || EF6 var objectStateEntry = entry.DelayedKey as ObjectStateEntry; #elif EFCORE var objectStateEntry = entry.DelayedKey as EntityEntry; #endif if (objectStateEntry != null) { #if EF5 || EF6 if (objectStateEntry.IsRelationship) { var values = objectStateEntry.CurrentValues; var leftKeys = (EntityKey)values.GetValue(0); var rightKeys = (EntityKey)values.GetValue(1); var leftRelationName = values.GetName(0); var rightRelationName = values.GetName(1); foreach (var keyValue in leftKeys.EntityKeyValues) { var auditEntryProperty = audit.Configuration.AuditEntryPropertyFactory != null? audit.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, leftRelationName, keyValue.Key, null, keyValue.Value)) : new AuditEntryProperty(); auditEntryProperty.Build(entry, leftRelationName, keyValue.Key, null, keyValue.Value); entry.Properties.Add(auditEntryProperty); } foreach (var keyValue in rightKeys.EntityKeyValues) { var auditEntryProperty = audit.Configuration.AuditEntryPropertyFactory != null? audit.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, rightRelationName, keyValue.Key, null, keyValue.Value)) : new AuditEntryProperty(); auditEntryProperty.Build(entry, rightRelationName, keyValue.Key, null, keyValue.Value); entry.Properties.Add(auditEntryProperty); } } else { foreach (var keyValue in objectStateEntry.EntityKey.EntityKeyValues) { var property = entry.Properties.FirstOrDefault(x => x.InternalPropertyName == keyValue.Key); // ENSURE the property is audited if (property != null) { property.NewValue = keyValue.Value; } } } } #elif EFCORE foreach (var keyValue in objectStateEntry.Metadata.GetKeys()) { var key = objectStateEntry.Property(keyValue.Properties[0].Name); var property = entry.Properties.FirstOrDefault(x => x.InternalPropertyName == keyValue.Properties[0].Name); // ENSURE the property is audited if (property != null) { property.NewValue = key.CurrentValue; } } } #endif } }
/// <summary>Audit entity deleted.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> #if EF5 || EF6 public static void AuditEntityDeleted(Audit audit, ObjectStateEntry objectStateEntry)
public static void AuditRelationDeleted(Audit audit, AuditEntry entry, ObjectStateEntry objectStateEntry)
/// <summary>Audit relationship added.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> #if EF5 || EF6 public static void AuditRelationAdded(Audit audit, ObjectStateEntry objectStateEntry)
/// <summary>Asynchronously audits and saves all changes made in this context to the underlying database.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <returns> /// A task that represents the asynchronous save operation. The task result contains the number of objects written /// to the underlying database /// </returns> public static Task<int> SaveChangesAsync(this DbContext context, Audit audit) { return context.SaveChangesAsync(audit, CancellationToken.None); }
/// <summary>Audit entity modified.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="entry">The entry.</param> /// <param name="objectStateEntry">The object state entry.</param> /// <param name="orginalRecord">The original record.</param> /// <param name="currentRecord">The current record.</param> /// <param name="prefix">The prefix.</param> public static void AuditEntityModified(Audit audit, AuditEntry entry, ObjectStateEntry objectStateEntry, DbDataRecord orginalRecord, DbUpdatableDataRecord currentRecord, string prefix = "") { bool hasModified = false; for (var i = 0; i < orginalRecord.FieldCount; i++) { var name = orginalRecord.GetName(i); var originalValue = orginalRecord.GetValue(i); var currentValue = currentRecord.GetValue(i); if (audit.Configuration.UseNullForDBNullValue && originalValue == DBNull.Value) { originalValue = null; } if (audit.Configuration.UseNullForDBNullValue && currentValue == DBNull.Value) { currentValue = null; } var valueRecord = originalValue as DbDataRecord; if (valueRecord != null) { // Complex Type AuditEntityModified(audit, entry, objectStateEntry, valueRecord, currentValue as DbUpdatableDataRecord, string.Concat(prefix, name, ".")); } else if (objectStateEntry.EntityKey.EntityKeyValues.Any(x => x.Key == name) || entry.Parent.CurrentOrDefaultConfiguration.IsAuditedProperty(entry.Entry, string.Concat(prefix, name))) { var isKey = objectStateEntry.EntityKey.EntityKeyValues.Any(x => x.Key == name); if (!audit.Configuration.IgnorePropertyUnchanged || isKey || !Equals(currentValue, originalValue)) { var auditEntryProperty = entry.Parent.Configuration.AuditEntryPropertyFactory != null? entry.Parent.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, string.Concat(prefix, name), originalValue, currentValue)) : new AuditEntryProperty(); auditEntryProperty.IsKey = isKey; auditEntryProperty.Build(entry, string.Concat(prefix, name), originalValue, currentRecord, i); entry.Properties.Add(auditEntryProperty); if (!isKey) { hasModified = true; } } } } if (audit.Configuration.IgnoreEntityUnchanged) { if (!hasModified) { entry.Properties.Clear(); } } }
public void Build(Audit parent, ObjectStateEntry entry)
private static void GrantDBContext_OnQtEFCommit(RpcContext rpcContext, Microsoft.EntityFrameworkCore.DbContext dbContext, DbInfo dbInfo, Z.EntityFramework.Plus.Audit audit) { var user = rpcContext.GetUserContext(); if (haveAudit(user)) { if (audit?.Entries == null) { return; } var auditData = new List <AuditData>(); try { audit.Entries = audit.Entries.Where(x => x.State == AuditEntryState.EntityModified || x.State == AuditEntryState.EntityDeleted).ToList(); //修正空审计记录 if (audit.Entries.Count() == 0) { return; } auditData = AuditTool.AuditConvertToArgs(dbContext.Database, user, audit, dbInfo); auditData?.ForEach(x => { if (!string.IsNullOrEmpty(rpcContext.Args.rid)) { x.TransactionId = rpcContext.Args.rid; } }); } catch (Exception ex) { logger.LogError(ex, "GrantDBContext_OnQtEFCommit error."); } AuditTool.SaveAuditData(dbContext.Database, auditData, dbInfo); } }
/// <summary>Adds audit entries before the save changes has been executed.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="context">The context used to audits and saves all changes made.</param> public static void PreSaveChanges(Audit audit, DbContext context) { #if EF5 || EF6 var objectContext = ((IObjectContextAdapter) context).ObjectContext; objectContext.DetectChanges(); var changes = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted); #elif EFCORE context.ChangeTracker.DetectChanges(); var changes = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted); #endif foreach (var objectStateEntry in changes) { #if EF5 || EF6 // Relationship if (objectStateEntry.IsRelationship) { // Relationship Added if (objectStateEntry.State == EntityState.Added && !audit.CurrentOrDefaultConfiguration.IgnoreRelationshipAdded) { AuditRelationAdded(audit, objectStateEntry); } // Relationship Deleted else if (objectStateEntry.State == EntityState.Deleted && !audit.CurrentOrDefaultConfiguration.IgnoreRelationshipDeleted) { AuditRelationDeleted(audit, objectStateEntry); } } // Entity else { #endif // Entity Added if (objectStateEntry.State == EntityState.Added && !audit.CurrentOrDefaultConfiguration.IgnoreEntityAdded && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { AuditEntityAdded(audit, objectStateEntry); } // Entity Deleted else if (objectStateEntry.State == EntityState.Deleted && !audit.CurrentOrDefaultConfiguration.IgnoreEntityDeleted && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { AuditEntityDeleted(audit, objectStateEntry); } // Entity Modified else if (objectStateEntry.State == EntityState.Modified && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { var auditState = audit.CurrentOrDefaultConfiguration.GetEntityModifiedState(objectStateEntry); // Entity Modified if (auditState == AuditEntryState.EntityModified && !audit.CurrentOrDefaultConfiguration.IgnoreEntityModified) { AuditEntityModified(audit, objectStateEntry, auditState); } // Entity Soft Added else if (auditState == AuditEntryState.EntitySoftAdded && !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftAdded) { AuditEntityModified(audit, objectStateEntry, auditState); } // Entity Soft Deleted else if (auditState == AuditEntryState.EntitySoftDeleted && !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftDeleted) { AuditEntityModified(audit, objectStateEntry, auditState); } } #if EF5 || EF6 } #endif } }
public AuditEntryFactoryArgs(Audit audit, ObjectStateEntry objectStateEntry, AuditEntryState auditEntryState)
/// <summary>Constructor.</summary> /// <param name="parent">The audit parent.</param> /// <param name="entry">The object state entry.</param> #if EF5 || EF6 public AuditEntry(Audit parent, ObjectStateEntry entry)
/// <summary>Asynchronously audits and saves all changes made in this context to the underlying database.</summary> /// <param name="context">The context used to audits and saves all changes made.</param> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <returns> /// A task that represents the asynchronous save operation. The task result contains the number of objects written /// to the underlying database /// </returns> public static Task <int> SaveChangesAsync(this DbContext context, Audit audit) { return(context.SaveChangesAsync(audit, CancellationToken.None)); }
/// <summary>Audit entity modified.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> #if EF5 || EF6 public static void AuditEntityModified(Audit audit, ObjectStateEntry objectStateEntry, AuditEntryState state)
public static void AuditRelationAdded(Audit audit, EntityEntry objectStateEntry) #endif { var entry = audit.Configuration.AuditEntryFactory != null? audit.Configuration.AuditEntryFactory(new AuditEntryFactoryArgs(audit, objectStateEntry, AuditEntryState.RelationshipAdded)) : new AuditEntry(); entry.Build(audit, objectStateEntry); entry.State = AuditEntryState.RelationshipAdded; var values = objectStateEntry.CurrentValues; var leftKeys = (EntityKey)values.GetValue(0); var rightKeys = (EntityKey)values.GetValue(1); if (leftKeys.IsTemporary || rightKeys.IsTemporary) { entry.DelayedKey = objectStateEntry; } else { var leftRelationName = values.GetName(0); var rightRelationName = values.GetName(1); foreach (var keyValue in leftKeys.EntityKeyValues) { var value = keyValue.Value; if (audit.Configuration.UseNullForDBNullValue && value == DBNull.Value) { value = null; } var auditEntryProperty = entry.Parent.Configuration.AuditEntryPropertyFactory != null? entry.Parent.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, leftRelationName, keyValue.Key, null, value)) : new AuditEntryProperty(); auditEntryProperty.Build(entry, leftRelationName, keyValue.Key, null, value); entry.Properties.Add(auditEntryProperty); } foreach (var keyValue in rightKeys.EntityKeyValues) { var value = keyValue.Value; if (audit.Configuration.UseNullForDBNullValue && value == DBNull.Value) { value = null; } var auditEntryProperty = entry.Parent.Configuration.AuditEntryPropertyFactory != null? entry.Parent.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, rightRelationName, keyValue.Key, null, value)) : new AuditEntryProperty(); auditEntryProperty.Build(entry, rightRelationName, keyValue.Key, null, value); entry.Properties.Add(auditEntryProperty); } } audit.Entries.Add(entry); }
/// <summary>Audit entity added.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="objectStateEntry">The object state entry.</param> #if EF5 || EF6 public static void AuditEntityAdded(Audit audit, ObjectStateEntry objectStateEntry)
/// <summary>Updates audit entries after the save changes has been executed.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> public static void PostSaveChanges(Audit audit) { foreach (var entry in audit.Entries) { if (entry.DelayedKey != null) { #if EF5 || EF6 var objectStateEntry = entry.DelayedKey as ObjectStateEntry; #elif EFCORE var objectStateEntry = entry.DelayedKey as EntityEntry; #endif if (objectStateEntry != null) { #if EF5 || EF6 if (objectStateEntry.IsRelationship) { var values = objectStateEntry.CurrentValues; var leftKeys = (EntityKey) values.GetValue(0); var rightKeys = (EntityKey) values.GetValue(1); var leftRelationName = values.GetName(0); var rightRelationName = values.GetName(1); foreach (var keyValue in leftKeys.EntityKeyValues) { entry.Properties.Add(new AuditEntryProperty(entry, leftRelationName, keyValue.Key, null, keyValue.Value)); } foreach (var keyValue in rightKeys.EntityKeyValues) { entry.Properties.Add(new AuditEntryProperty(entry, rightRelationName, keyValue.Key, null, keyValue.Value)); } } else { foreach (var keyValue in objectStateEntry.EntityKey.EntityKeyValues) { var property = entry.Properties.FirstOrDefault(x => x.PropertyName == keyValue.Key); // ENSURE the property is audited if (property != null) { property.NewValue = keyValue.Value; } } } } #elif EFCORE foreach (var keyValue in objectStateEntry.Metadata.GetKeys()) { var key = objectStateEntry.Property(keyValue.Properties[0].Name); var property = entry.Properties.FirstOrDefault(x => x.PropertyName == keyValue.Properties[0].Name); // ENSURE the property is audited if (property != null) { property.NewValue = key.CurrentValue; } } } #endif } }
/// <summary>Adds audit entries before the save changes has been executed.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> /// <param name="context">The context used to audits and saves all changes made.</param> public static void PreSaveChanges(Audit audit, DbContext context) { #if EF5 || EF6 var objectContext = ((IObjectContextAdapter)context).ObjectContext; objectContext.DetectChanges(); var changes = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted); #elif EFCORE context.ChangeTracker.DetectChanges(); var changes = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted); #endif foreach (var objectStateEntry in changes) { #if EF5 || EF6 // Relationship if (objectStateEntry.IsRelationship) { // Relationship Added if (objectStateEntry.State == EntityState.Added && !audit.CurrentOrDefaultConfiguration.IgnoreRelationshipAdded) { AuditRelationAdded(audit, objectStateEntry); } // Relationship Deleted else if (objectStateEntry.State == EntityState.Deleted && !audit.CurrentOrDefaultConfiguration.IgnoreRelationshipDeleted) { AuditRelationDeleted(audit, objectStateEntry); } } // Entity else { #endif // Entity Added if (objectStateEntry.State == EntityState.Added && !audit.CurrentOrDefaultConfiguration.IgnoreEntityAdded && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { AuditEntityAdded(audit, objectStateEntry); } // Entity Deleted else if (objectStateEntry.State == EntityState.Deleted && !audit.CurrentOrDefaultConfiguration.IgnoreEntityDeleted && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { AuditEntityDeleted(audit, objectStateEntry); } // Entity Modified else if (objectStateEntry.State == EntityState.Modified && audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry)) { var auditState = audit.CurrentOrDefaultConfiguration.GetEntityModifiedState(objectStateEntry); // Entity Modified if (auditState == AuditEntryState.EntityModified && !audit.CurrentOrDefaultConfiguration.IgnoreEntityModified) { AuditEntityModified(audit, objectStateEntry, auditState); } // Entity Soft Added else if (auditState == AuditEntryState.EntitySoftAdded && !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftAdded) { AuditEntityModified(audit, objectStateEntry, auditState); } // Entity Soft Deleted else if (auditState == AuditEntryState.EntitySoftDeleted && !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftDeleted) { AuditEntityModified(audit, objectStateEntry, auditState); } } #if EF5 || EF6 } #endif } }
/// <summary>Updates audit entries after the save changes has been executed.</summary> /// <param name="audit">The audit to use to add changes made to the context.</param> public static void PostSaveChanges(Audit audit) { foreach (var entry in audit.Entries) { switch (entry.State) { case AuditEntryState.EntityAdded: #if EF5 || EF6 AuditEntityAdded(entry, entry.Entry, entry.Entry.CurrentValues); #elif EFCORE AuditEntityAdded(entry, entry.Entry); #endif break; case AuditEntryState.EntityDeleted: case AuditEntryState.RelationshipDeleted: break; case AuditEntryState.EntityModified: case AuditEntryState.EntitySoftAdded: case AuditEntryState.EntitySoftDeleted: #if EF5 || EF6 foreach (var property in entry.Properties) { if (!property.IsValueSet) { var currentValue = property.DbUpdatableDataRecord.GetValue(property.DbUpdatableDataRecordPosition); if (audit.Configuration.UseNullForDBNullValue && currentValue == DBNull.Value) { currentValue = null; } property.NewValue = currentValue; } } #elif EFCORE if (entry.State == AuditEntryState.EntityModified && entry.Entry.State == EntityState.Detached) { // Oops! It's has not beed modified but deleted entry.State = AuditEntryState.EntityDeleted; var listToRemove = entry.Properties.Where(x => !x.PropertyEntry.Metadata.IsKey()).ToList(); listToRemove.ForEach(x => entry.Properties.Remove(x)); } else { foreach (var property in entry.Properties) { if (!property.IsValueSet) { var currentValue = property.PropertyEntry.CurrentValue; property.NewValue = currentValue; } } } #endif break; case AuditEntryState.RelationshipAdded: #if EF5 || EF6 AuditRelationAdded(audit, entry, entry.Entry); #endif break; } } // foreach (var entry in audit.Entries) // { // if (entry.DelayedKey != null) // { //#if EF5 || EF6 // var objectStateEntry = entry.DelayedKey as ObjectStateEntry; //#elif EFCORE // var objectStateEntry = entry.DelayedKey as EntityEntry; //#endif // if (objectStateEntry != null) // { //#if EF5 || EF6 // if (objectStateEntry.IsRelationship) // { // var values = objectStateEntry.CurrentValues; // var leftKeys = (EntityKey) values.GetValue(0); // var rightKeys = (EntityKey) values.GetValue(1); // var leftRelationName = values.GetName(0); // var rightRelationName = values.GetName(1); // foreach (var keyValue in leftKeys.EntityKeyValues) // { // var auditEntryProperty = audit.Configuration.AuditEntryPropertyFactory != null ? // audit.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, leftRelationName, keyValue.Key, null, keyValue.Value)) : // new AuditEntryProperty(); // auditEntryProperty.Build(entry, leftRelationName, keyValue.Key, null, keyValue.Value); // entry.Properties.Add(auditEntryProperty); // } // foreach (var keyValue in rightKeys.EntityKeyValues) // { // var auditEntryProperty = audit.Configuration.AuditEntryPropertyFactory != null ? // audit.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, rightRelationName, keyValue.Key, null, keyValue.Value)) : // new AuditEntryProperty(); // auditEntryProperty.Build(entry, rightRelationName, keyValue.Key, null, keyValue.Value); // entry.Properties.Add(auditEntryProperty); // } // } // else // { // foreach (var keyValue in objectStateEntry.EntityKey.EntityKeyValues) // { // var property = entry.Properties.FirstOrDefault(x => x.InternalPropertyName == keyValue.Key); // // ENSURE the property is audited // if (property != null) // { // property.NewValue = keyValue.Value; // } // } // } // } //#elif EFCORE // foreach (var keyValue in objectStateEntry.Metadata.GetKeys()) // { // var key = objectStateEntry.Property(keyValue.Properties[0].Name); // var property = entry.Properties.FirstOrDefault(x => x.InternalPropertyName == keyValue.Properties[0].Name); // // ENSURE the property is audited // if (property != null) // { // property.NewValue = key.CurrentValue; // } // } // } //#endif // } //} }