I've read multiple posts about how to implement an audit log using entity framework. I currently have the audit logic embedded in the SaveChanges
method in the DbContext
. Please keep in mind that the code below is an EF4/5 implementation and I'm preparing to update to EF6.
namespace Database {
public class AuditDetails {
public string RemoteHost { get; set; }
public string RevisionUser { get; set; }
public string RevisionNotes { get; set; }
public DateTime RevisionDateTime { get; set; }
}
public class MyContext : DbContext {
// ... Unrelated overrides here ... //
public void SaveChanges(AuditDetails auditDetails) {
var saveCount = ProcessConcurrency();
var items = ChangeTracker.Entries<MyEntity>().ToList();
if (saveCount <= 0 || items == null || !items.Any() || auditDetails == null) return;
foreach (var item in items.Select(entityEntry => entityEntry.Entity).Where(i => i != null)) {
// ... create audit log using AuditDetails values ... //
}
// ... and call base.SaveChanges() ... //
}
}
}
So the questions would be:
SavingChanges
event handler? Or possibly split the functionality to use both?AuditDetails
information preclude using SavingChanges
?SaveChanges
that accepts the Boolean argument for use in transactions. How would adding that change the solution?In Summary:
SaveChanges
and when/why would you prefer to use a SavingChanges
event handler?I don't think it really matters in most cases. There are three situations I can think of that demand one of both options:
SaveChanges
should be overridden completely, so base.SaveChanges
should not be called: only an override can do this.
Another class is involved in what happens on saving changes: only the event can do that. (Or maybe I should say: an event would be the obvious pattern to choose).
You want to extend SaveChanges
optionally. To my taste it's cleaner to activate the event in the constructor by some parameter than to start an override with if (option)
, where option
must have been stored as a member variable.
In all other cases I'd always use the override. The event requires the ObjectContext
to be dug up first (because it's ObjectContext.SavingChanges
). And an override is hard-wired. An event subscription can always break somehow in code maintenance.