4

I'm using the Entity Framework to construct a basic repository to add/delete/update Customer records.

One thing I want is to be able to have Customer row auditing so that I have a second table CustomerAudit that should get an entry added every time you add/update/delete a row. In the old wyrld this would be done with a database trigger on update/on delete/on insert etc. Now, I'm trying to do it by overriding the SaveChanges() method of the DBContext object, leveraging the ChangeTracker object and using that to create an audit record based on the data being saved/updated with the current date time and inserting that alongside the actual row. Code below.

The problem I have is that when you update or delete, this works fine as it writes the most recent record to the audit table which will have either the updated values or the final values before deletion, along with the current timestamp of when this activity occurred.

When you add a record though, it inserts a record in the audit table, but as the actual row hasn't been inserted yet (with identity insert) you dont yet have the CustomerId and so it inserts an audit record with the correct data but with a CustomerId of 0, which is no good for auditing.

Any thoughts on how I can get the auditing working for adding records to?

 public class CustomerDbContext : DbContext 
    {
        public CustomerDbContext()
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<CustomerDbContext>());
        }

        public DbSet<Customer> Customers { get; set; }
        public DbSet<CustomerAudit> CustomerAudits { get; set; }

        public override int SaveChanges()
        {
            // Get all Added/Deleted/Modified entities (not Unmodified or Detached)
            foreach (var ent in ChangeTracker.Entries().Where(p => p.State == System.Data.EntityState.Added || p.State == System.Data.EntityState.Deleted || p.State == System.Data.EntityState.Modified))
            {
                var auditRecord = GetAuditRecord(ent);
                if (auditRecord != null)
                    CustomerAudits.Add(auditRecord);                
            }

            // Call the original SaveChanges(), which will save both the changes made and the audit records
            return base.SaveChanges();
        }

        private static CustomerAudit GetAuditRecord(DbEntityEntry dbEntry)
        {
            var changedRecord = dbEntry.Entity as Customer;
            return changedRecord == null ? null : new CustomerAudit(changedRecord);
        }
    }
1
  • Another solution, which probably is unpractical for you now because you already have the models created, would be to change the PK type from int to GUID. The GUID will be generated when instantiating a Customer entity, and you will know in advance what value will have (customer.Id == '4705b72f-1e5b-4d0c-90d9-c235750f8b13') Commented Sep 1, 2014 at 7:03

2 Answers 2

3

Get the entries and save them to a list, then save the changes, storing the result of the base.SaveChanges() call in a variable, then go through your list of changes you created and create your audit entities from that, then return base.SaveChanges() + yourPriorSaveChangesResultVariable;

Sign up to request clarification or add additional context in comments.

Comments

2

The answer by @Rob G has solved the purpose though, but here the Audit is done in two transactions. Fist is to Insert the Customer row and second transaction with the CustomerId to CustomerAudit table.

I think it is better to create a Foreign Key relation with CustomerId in these tables will generate the same Id for CustomerAudit table as well and that too in the same transaction.

I am new in sharing my ideas to the stackoverflow, but getting help from this for quite long.

Please comment if any.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.