Entity Framework 6: audit/track changes

巧了我就是萌 提交于 2019-12-17 05:34:25

问题


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.


回答1:


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();
}



回答2:


There is nuget package for this https://www.nuget.org/packages/TrackerEnabledDbContext

Source: https://github.com/bilal-fazlani/tracker-enabled-dbcontext




回答3:


There is one way to do it: you can create a partial class that is the same name as your object context and implement an override of the SaveChanges method. In this override you can look at all the changes that will be pushed to the DB and process them.

You can process them any way you like, in the following example I created an interface IAutoTimestampEntity that contained a creation date and a modification date. Any object of this type would be automatically updated with the time of change.

public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
    var timestamp = DateTime.Now;

    foreach (var InsertedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
    {
        InsertedAutoTimestampEntity.CreationDate = timestamp;
        InsertedAutoTimestampEntity.ModificationDate = timestamp;
    }

    foreach (var UpdatedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
    {
        UpdatedAutoTimestampEntity.ModificationDate = timestamp;
    }

    return base.SaveChanges(options);
}

You can use the same principle, or you can look at the type of each changed entity in details. I like the declarative aspect of the interface though. It lets you expose one aspect of automation explicitly instead of letting it be done silently by the EF layer.

If you have a DbContext instead of an ObjectContext, cast your DbContext to IObjectContextAdapter to access the ObjectStateManager



来源:https://stackoverflow.com/questions/26355486/entity-framework-6-audit-track-changes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!