locked
How keep the original model data when execute an Edit on MVC? RRS feed

  • Question

  • User-1651604128 posted

    I am trying to implement an Audit trail in my mvc web app, the Add and Delete is easy to implement, but I have a problem in Editing an existing record.

    Basically, for each editing, I need to compare each field between current UI field value and the existing value in database, and create a change log in Log table.

    so I am trying to do something like this:

    [HttpPost]
            public ActionResult Edit(ProdViewModel viewModel, string button)
            {
    
                ProdViewModel OrigAIGModel = viewModel; //I want to keep the original model data for comparing later,
                tbl_Production NewProdModel = null;
               .......
    
    
               try
                {
                    if (ModelState.IsValid)
                    {
                      int prodID=  viewModel.SaveChanges();  //Update the record            
    
                        if (prodID > 0)
                        {
                            //after successful update above, I need to compare the data below and create a audit trail.
                          // UpdateAuditTrail(ProdViewModel,NewProdModel.GetByID(prodID));
                        //here I expect to pass the old model data and new model data,
                    //But the ProdViewModel is not the old model data, it is the updated model data, the ProdViewModel and NewProdModel is equivelent, 
                            return RedirectToAction("Edit", new { id = ProdID });
                        }
                    }
                 return View(viewModel);
    

    Is there any way to keep the original model data before the  "viewModel.SaveChanges(); ", so I can compare the two models (old model and new model ) data for auditing purpose?

    Or if there is any other better solutions?

    Any help is highly appreciated!

    Monday, April 15, 2019 6:35 PM

Answers

  • User2053451246 posted

    Retrieve the entity from the database first thing in your POST method.

    var fetched = db.Table.Find(id);

    if(fetched.Field != posted.Field)

    {

    ...do something to log

    fetched.Field = posted.Field

    }

    Then just remember to update the fetched entry to the database (instead of the posted one).

    db.entry(fetched).State = EntityState.Modified;

    db.SaveChanges();

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 15, 2019 7:28 PM
  • User-1651604128 posted

    Retrieve the entity from the database first thing in your POST method.

    var fetched = db.Table.Find(id);

    if(fetched.Field != posted.Field)

    {

    ...do something to log

    fetched.Field = posted.Field

    }

    Then just remember to update the fetched entry to the database (instead of the posted one).

    db.entry(fetched).State = EntityState.Modified;

    db.SaveChanges();

    Thank you so much, this is an easy and simple solution, works very well.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, April 16, 2019 6:40 PM

All replies

  • User475983607 posted

    This should be handled in the database using an UPDATE trigger.

    Google has a lot of information on the subject

    https://stackoverflow.com/questions/12137102/sql-update-trigger-only-when-column-is-modified

    SQL UPDATE Trigger reference

    https://docs.microsoft.com/en-us/sql/t-sql/functions/update-trigger-functions-transact-sql?view=sql-server-2017

    Monday, April 15, 2019 7:09 PM
  • User2053451246 posted

    Retrieve the entity from the database first thing in your POST method.

    var fetched = db.Table.Find(id);

    if(fetched.Field != posted.Field)

    {

    ...do something to log

    fetched.Field = posted.Field

    }

    Then just remember to update the fetched entry to the database (instead of the posted one).

    db.entry(fetched).State = EntityState.Modified;

    db.SaveChanges();

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 15, 2019 7:28 PM
  • User-474980206 posted

    you should also and an update timestamp, to test if the save was done after the page read, and page post back.

    Monday, April 15, 2019 7:33 PM
  • User-1651604128 posted

    This should be handled in the database using an UPDATE trigger.

    Google has a lot of information on the subject

    https://stackoverflow.com/questions/12137102/sql-update-trigger-only-when-column-is-modified

    SQL UPDATE Trigger reference

    https://docs.microsoft.com/en-us/sql/t-sql/functions/update-trigger-functions-transact-sql?view=sql-server-2017

    It seems the Update trigger is doing some coding in SQL side, no quite understand how to apply it in my situation,

    I am wondering if there is any way to do it in controller side based on the C# codes I posted.

    Thanks a lot,

    Monday, April 15, 2019 7:35 PM
  • User-474980206 posted

    for an update, your code should lookup the old entity by the encrypted key passed by the post back view model.  then apply the post back view model values that are allowed to be modified by the user to the entity. You can then use change tracking for audit.  then save changes. 

    hint: you can use attributes and reflection to apply changes from the view model to the entity model, or use a tool like automapper.

    Monday, April 15, 2019 9:43 PM
  • User-1651604128 posted

    for an update, your code should lookup the old entity by the encrypted key passed by the post back view model.  then apply the post back view model values that are allowed to be modified by the user to the entity. You can then use change tracking for audit.  then save changes. 

    hint: you can use attributes and reflection to apply changes from the view model to the entity model, or use a tool like automapper.

    Sounds this is a better way, I appreciate if you can provide an example based on my example codes provided, much appreciated,

    Monday, April 15, 2019 10:25 PM
  • User-1651604128 posted

    Retrieve the entity from the database first thing in your POST method.

    var fetched = db.Table.Find(id);

    if(fetched.Field != posted.Field)

    {

    ...do something to log

    fetched.Field = posted.Field

    }

    Then just remember to update the fetched entry to the database (instead of the posted one).

    db.entry(fetched).State = EntityState.Modified;

    db.SaveChanges();

    Thank you so much, this is an easy and simple solution, works very well.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, April 16, 2019 6:40 PM