2

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:

  • Is there a benefit to moving this to a SavingChanges event handler? Or possibly split the functionality to use both?
  • Does the AuditDetails information preclude using SavingChanges?
  • I do not have an override for SaveChanges that accepts the Boolean argument for use in transactions. How would adding that change the solution?

In Summary:

  • When would you override/implement SaveChanges and when/why would you prefer to use a SavingChanges event handler?
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Eris
  • 7,378
  • 1
  • 30
  • 45
  • And as an added bonus, which may be better as a new question: Would switching to an Async API change which solution to use? – Eris Jan 09 '15 at 21:40
  • Usually if you are inheriting from a class, you would override the method that gets called when the event happens, the base version of which actually calls the event. You use the event when you are handling it from a different class. – Matt Burland Jan 09 '15 at 21:41
  • Related question with implementation of `SavingChanges` event: http://stackoverflow.com/questions/3808217/entity-framework-auditing-activity – Eris Jan 12 '15 at 23:05

1 Answers1

2

I don't think it really matters in most cases. There are three situations I can think of that demand one of both options:

  1. SaveChanges should be overridden completely, so base.SaveChanges should not be called: only an override can do this.

  2. 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).

  3. 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.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • I'm leaning toward your second item. This way I can implement auditing as a "plugin" instead of baked into the context. – Eris Jan 09 '15 at 22:48
  • Sure, that would be a valid reason. Even then, I think I would prefer to create my own event based on `DbContext`, probably carrying the context in its args object. – Gert Arnold Jan 09 '15 at 22:50