Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Partial class to override SaveChanges of DbContext and use it for creating audit trail
public partial class CustomDbContext: DbContext
{
public override int SaveChanges()
{
// Get all Added/Deleted/Modified entities (not Unmodified or Detached)
//you can get updated and deleted in same collection. I am doing so for ease of purpose
//getting added entries in different collection to fetch their generated ids and then log them
var addedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Added).ToList();
var updatedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).ToList();
var deletedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted).ToList();
foreach (var entry in updatedEntries)
{
ApplyAuditLog(entry);
}
foreach (var entry in deletedEntries)
{
ApplyAuditLog(entry);
}
int changes = base.SaveChanges();
foreach (var entry in addedEntries)
{
ApplyAuditLog(entry);
}
base.SaveChanges();
return changes;
}
/// <summary>
/// code to enter values in audit table
/// </summary>
/// <param name="entry"></param>
/// <param name="auditType"></param>
private void ApplyAuditLog(DbEntityEntry entry)
{
//get table name of entry
string tableName = GetTableName(entry);
//exlude audit table from getting audited
if (!tableName.Equals("Audit", StringComparison.OrdinalIgnoreCase))
{
//code to get primary key (id) of object which is updated
var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
int primaryKeyOfEntity = (int)objectStateEntry.EntityKey.EntityKeyValues[0].Value;
DateTime currentDateTime = DateTime.Now;
//code to convert the updated/added/deleted entry to json using newtonsoft json nuget package
string serializedJson = JsonConvert.SerializeObject(entry.CurrentValues.ToObject(), Formatting.Indented, new JsonSerializerSettings
{
//below code ignores the circular references. Main reason XML is not used as this was so wasy in JSON
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
Audit auditTrail = new Audit()
{
TimeStamp = currentDateTime,
AuthenticatedUser = {/* code to log authenticated user */ },
LinkedID = primaryKeyOfEntity,
AuditType = {/*create/update/delete/or read. Write your own logic here */ },
TableName = tableName,
NewValue = serializedJson
};
//you can write code here to generated checksum using algo like SHA1, MD5 and then update it in audit trail
//string checksumValue = GetChecksumValueFromTrail(auditTrail);
//write code to add entry in audit table here like below
//Audit.Add(auditTrail);
}
}
/// <summary>
/// method to fetch table name of updated entity
/// </summary>
/// <param name="dbEntityEntry"></param>
/// <returns></returns>
private string GetTableName(DbEntityEntry dbEntityEntry)
{
ObjectContext objectContext = ((IObjectContextAdapter)this).ObjectContext;
Type entityType = dbEntityEntry.Entity.GetType();
if (entityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies")
entityType = entityType.BaseType;
string entityTypeName = entityType.Name;
EntityContainer container =
objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace);
string entitySetName = (from meta in container.BaseEntitySets
where meta.ElementType.Name == entityTypeName
select meta.Name).First();
return entitySetName;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.