I am trying to implement a constrained ‘audit log’ of property changes to a properties in a set of classes. I have successfully found out how to set CreatedOn|ModifiedOn type properties, but am failing to find out how to ‘find’ the property that has been modified.
Example:
public class TestContext : DbContext
{
public override int SaveChanges()
{
var utcNowAuditDate = DateTime.UtcNow;
var changeSet = ChangeTracker.Entries<IAuditable>();
if (changeSet != null)
foreach (DbEntityEntry<IAuditable> dbEntityEntry in changeSet)
{
switch (dbEntityEntry.State)
{
case EntityState.Added:
dbEntityEntry.Entity.CreatedOn = utcNowAuditDate;
dbEntityEntry.Entity.ModifiedOn = utcNowAuditDate;
break;
case EntityState.Modified:
dbEntityEntry.Entity.ModifiedOn = utcNowAuditDate;
//some way to access the name and value of property that changed here
var changedThing = SomeMethodHere(dbEntityEntry);
Log.WriteAudit("Entry: {0} Origianl :{1} New: {2}", changedThing.Name,
changedThing.OrigianlValue, changedThing.NewValue)
break;
}
}
return base.SaveChanges();
}
}
So, is there a way to access the property that changed with this level of detail in EF 4.1 DbContext?
Very, very rough idea:
I have no clue if this would really work in detail, but this is something I would try as a first step. Of course there could be more then one property which has changed, therefore the loop and perhaps multiple calls of
WriteAudit.The reflection stuff inside of SaveChanges could become a performance nightmare though.
Edit
Perhaps it is better to access the underlying
ObjectContext. Then something like this is possible:I’ve used this myself in EF 4.0. I cannot find a corresponding method to
GetModifiedProperties(which is the key to avoid the reflection code) in theDbContextAPI.Edit 2
Important: When working with POCO entities the code above needs to call
DbContext.ChangeTracker.DetectChanges()at the beginning. The reason is thatbase.SaveChangesis called too late here (at the end of the method).base.SaveChangescallsDetectChangesinternally, but because we want to analyze and log the changes before, we must callDetectChangesmanually so that EF can find all modified properties and set the states in the change tracker correctly.There are possible situations where the code can work without calling
DetectChanges, for example if DbContext/DbSet methods likeAddorRemoveare used after the last property modifications are made since these methods also callDetectChangesinternally. But if for instance an entity is just loaded from DB, a few properties are changed and then this derivedSaveChangesis called, automatic change detection would not happen beforebase.SaveChanges, finally resulting in missing log entries for modified properties.I’ve updated the code above accordingly.