Last active
September 16, 2020 04:28
-
-
Save garima2510/3da164fd96a8cab0e16e04fb79a08bd4 to your computer and use it in GitHub Desktop.
Partial class to override SaveChanges of DbContext and use it for creating audit trail
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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