Search code examples
c#entity-frameworkentity-framework-6auditaudit-trail

Entity Framework 6: audit/track changes


I have my core project in C#.

I work on a database, where some tables have the columns "user_mod" and "date_mod" for sign who and when made some mods and the same with "data_new" and "user_new".

My question: is there a way to centralize this and make this data inserted automatically, where I create the instance of dbContext?

If not, I will use an audit trail tool. I have seen some of these, but there is a problem: all of these, require some code in my model. But I don't want to write in my model, because if I have to change it, I will lost the mods. Is it possible use an audit trail for EF6 without writing in the model file(s)? How?

EDIT:

My attempt to override the saveChanges.

public partial class PieEntities : DbContext
{
    public override int SaveChanges(System.Data.Objects.SaveOptions options)
    {
        var timestamp = DateTime.Now;

        EntityState es = EntityState.Added;
        ObjectStateManager o = new ObjectStateManager();

        foreach (ObjectStateEntry entry in o.GetObjectStateEntries(EntityState.Added ))  {
            if (entry.Entity.GetType() == typeof(TabImpianti)) {
                TabImpianti impianto = entry.Entity as TabImpianti;
                impianto.DATA_INS = timestamp;
                impianto.DATA_MOD = timestamp;
                string u = mdlImpostazioni.p.UserName;
                impianto.USER_INS = u;
                impianto.USER_MOD = u;
            }
        }
        return base.SaveChanges(options);
    }
}

UPDATE: I've summarized the solution here.


Solution

  • If using EF6's DbContext you can use ChangeTracker in SaveChanges override to find added/modified entities of custom type, for example IAuditedEntity.

    public interface IAuditedEntity {
      string CreatedBy { get; set; }
      DateTime CreatedAt { get; set; }
      string LastModifiedBy { get; set; }
      DateTime LastModifiedAt { get; set; }
    }
    
    public override int SaveChanges() {
      var addedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
        .Where(p => p.State == EntityState.Added)
        .Select(p => p.Entity);
    
      var modifiedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
        .Where(p => p.State == EntityState.Modified)
        .Select(p => p.Entity);
    
      var now = DateTime.UtcNow;
    
      foreach (var added in addedAuditedEntities) {
        added.CreatedAt = now;
        added.LastModifiedAt = now;
      }
    
      foreach (var modified in modifiedAuditedEntities) {
        modified.LastModifiedAt = now;
      }
    
      return base.SaveChanges();
    }