Search code examples
c#entity-frameworkauditobjectstatemanager

EF ObjectStateEntry OriginalValues contains CurrentValues


I am trying to override Entity Framework's SaveChanges() method to save auditing information. I begin with the following:

public override int SaveChanges()
{
    ChangeTracker.DetectChanges();
    ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;
    List<ObjectStateEntry> objectStateEntryList = ctx.ObjectStateManager.GetObjectStateEntries(
                                                         EntityState.Added
                                                       | EntityState.Modified
                                                       | EntityState.Deleted).ToList();

    foreach (ObjectStateEntry entry in objectStateEntryList)
    {
        if (!entry.IsRelationship)
        {
            //Code that checks and records which entity (table) is being worked with
            ...

            foreach (string propertyName in entry.GetModifiedProperties())
            {
                DbDataRecord original = entry.OriginalValues;
                string oldValue = original.GetValue(original.GetOrdinal(propertyName)).ToString();

                CurrentValueRecord current = entry.CurrentValues;
                string newValue = current.GetValue(current.GetOrdinal(propertyName)).ToString();

                if (oldValue != newValue)
                {
                    AuditEntityField field = new AuditEntityField
                    {
                        FieldName = propertyName,
                        OldValue = oldValue,
                        NewValue = newValue,
                        Timestamp = auditEntity.Timestamp
                    };
                    auditEntity.AuditEntityField.Add(field);
                }
            }
        }
    }
}

Problem I'm having is that the values I get in entry.OriginalValues and in entry.CurrentValues is always the new updated value:

Audit Entity State


Solution

  • The problem has been found:

    public ActionResult Edit(Branch branch)
    {
        if (ModelState.IsValid)
        {
            db.Entry(branch).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(branch);
    }
    

    Saving an update in the above way seems to cause the ChangeTracker to not pick up the old values. I fixed this by simply making use of ViewModels for all the required updates:

    public ActionResult Edit(BranchViewModel model)
    {
        if (ModelState.IsValid)
        {
            Branch branch = db.Branch.Find(model.BranchId);
    
            if (branch.BranchName != model.BranchName)
            {
                branch.BranchName = model.BranchName;
                db.SaveChanges();
            }
            return RedirectToAction("Index");
        }
        return View(model);
    }