Reputation: 1336
I am developing an MVC 5 application using EF 6. The auto-generated POST method for Edit is:
public ActionResult Edit([Bind(Include = "Id,Name,Address,Phone,SSNo,D1")] ABC abc)
{
if (ModelState.IsValid)
{
db.Entry(abc).State = EntityState.Modified;
db.SaveChanges();
}
return View(abc);
}
Is there any procedure/method by which I can get that which entries are modified and what were the original values of those entries. I have tried the method marked as an answer in this question but it didn't get any changes although changes have been made, i.e. the loop does not iterates.
My code is:
public ActionResult Edit([Bind(Include = "Id,Name,Address,Phone,SSNo,D1")] ABC abc)
{
if (ModelState.IsValid)
{
db.ABCs.Attach(abc);
var myObjectState = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager.GetObjectStateEntry(abc);
var modifiedProperties = myObjectState.GetModifiedProperties();
foreach (var propName in modifiedProperties)
{
Console.WriteLine("Property {0} changed from {1} to {2}",
propName,
myObjectState.OriginalValues[propName],
myObjectState.CurrentValues[propName]);
}
Console.ReadKey();
db.Entry(abc).State = EntityState.Modified;
db.SaveChanges();
return Json(abc);
}
return View(abc);
}
ABC model contains many values other than mentioned in method parameters, but I am only passing those which can be edited
What I am trying to do is to maintain a log in my database of all the changes made to a document. I want to include only the changes and the original values before modification in the log not the complete record.
How can I get this?
Upvotes: 3
Views: 1128
Reputation: 7230
I implemented this extension method for you:
namespace YourProject.Extensions
{
public static class ModelExtensions
{
public static IEnumerable<KeyValuePair<string, object>> ModifiedValues<T>(this T obj, T modifiedObject)
{
foreach (var property in typeof(T).GetProperties().Where(p => !p.GetGetMethod().IsVirtual))
{
if (property.GetValue(obj).ToString() != property.GetValue(modifiedObject).ToString())
{
yield return new KeyValuePair<string, object>(property.Name, property.GetValue(modifiedObject));
}
}
}
}
}
It's neither the fastest nor the most efficient, but worked in my tests.
Use:
var originalEntity = await db.Entities.AsNoTracking().FirstOrDefaultAsync(e => e.EntityId == modifiedEntity.EntityId);
var modifiedValues = originalEntity.ModifiedValues<MyEntity>(modifiedEntity).ToList();
Upvotes: 3