entity-frameworksavechangesaudit-logging

access id of added entity before SaveChanges() is called


i'm using EF 4.3.1, I've overridden the SaveChanges() on the context so that I can get a list of the objects and their states and create entries in my audit log table. I need to store the id of the record in the audit log table so i have a reference to it. This is a problem when records are inserted, as I don't have access to the id before it's saved. Is there any way of getting the id at that point?

public override int SaveChanges()
{
        ChangeTracker.DetectChanges();

        var objectStateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager;
        var modifiedAuditableEntities = objectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added).Where(e => (IAuditable)e.Entity != null);

        foreach (var entry in modifiedAuditableEntities)
        {
            var entity = (IAuditable)entry.Entity;

            if (entity != null)
            {
                switch (entry.State)
                {
                    case EntityState.Added:
                        entity.IsAdded = true;
                        break;
                    case EntityState.Deleted:
                        entity.IsDeleted = true;
                        break;
                    case EntityState.Modified:
                        entity.IsModified = true;
                        break;
                }

                this.EntitySet<AuditLogEntry>().Add(this.auditLogService.CreateAuditLogEntryForEntity((IAuditable)entry.Entity));
            }
        return base.SaveChanges();
}

Solution

  • If your goal is that you want both your save, and your audit log to be created at the same time, you could wrap it in a transaction scope so your method to be atomic.

        public override int SaveChanges()
        {
            ChangeTracker.DetectChanges();
            using (var scope = new TransactionScope())
            {
                var objectStateManager = ((IObjectContextAdapter) this).ObjectContext.ObjectStateManager;
                var modifiedAuditableEntities =
                    objectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added).Where(
                        e => (IAuditable) e.Entity != null);
                var result = base.SaveChanges();
                foreach (var entry in modifiedAuditableEntities)
                {
                    var entity = (IAuditable) entry.Entity;
    
                    if (entity != null)
                    {
                        switch (entry.State)
                        {
                            case EntityState.Added:
                                entity.IsAdded = true;
                                break;
                            case EntityState.Deleted:
                                entity.IsDeleted = true;
                                break;
                            case EntityState.Modified:
                                entity.IsModified = true;
                                break;
                        }
    
                        this.EntitySet<AuditLogEntry>().Add(
                            this.auditLogService.CreateAuditLogEntryForEntity((IAuditable) entry.Entity));
                    }
                }
                base.SaveChanges();
    
                scope.Complete();
                return result;
            }
        }