问题
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