How keep original value for some field when execute Edit on MVC?

37,156

Solution 1

Fetch the existing version from the database, and then change just the 'modifiable' fields:

public ActionResult EditAdmin(User user)
{ 
    var currentPerson = db.Persons.FirstOrDefault(p => p.id = user.id);
    if (currentPerson == null)
        return HttpNotFound();

    currentPerson.Name = user.Name;
    currentPerson.Sex = user.Sex;
    // Id and Password are not updated.

    db.SaveChanges();
}
  • You might also want to do some optimistic concurrency checking as well, to ensure that the version being updated, is in fact current. Ideally, if you have a timestamp, use this, otherwise, you are faced with comparing all fields.

Edit
See also @Kris' comment and Ric's point about creating tailored view models and hence NOT polluting your views with ORM / data tier entities. I also still contend you need to carry a timestamp or hash through the ViewModel to prevent the last one wins overwriting problem.

Solution 2

You could and actually should make a specific viewmodel for your edit page. Like:

public class UserViewModel
{
    public string Name {get; set;}
    public bool Sex {get; set;}
}

Then instead of returning the complete user to and from the view, use the UserViewModel.

public ActionResult EditAdmin(int userId)
{ 
        User user = persons.Users.Find(userId);
        return View(new UserViewModel 
            { 
                Id = user.Id,
                Name = user.Name, 
                Sex = user.Sex 
            });
}

[HttpPost]
public ActionResult EditAdmin(UserViewModel user)
{ 
        var dbUser = persons.Users.Find(user.Id);
        dbUser.Name = user.Name;
        dbUser.Sex = user.Sex;

        persons.Entry(dbUser).State = EntityState.Modified;
        persons.SaveChanges();
}

Solution 3

Here is something I just learned how to do for Posting the data to a database and excluding other fields. I only wanted to post 1 change to my database on PIVPrinted checkbox.

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult PrintDetails([Bind(Include = "PatientID,LastName,FirstName,PatientDOB,PIVCompleted,PIVPrinted")] PIV pIV,
        string command)
    {

        if (command.Equals("Print Completed"))

        {
            pIV.PIVPrinted = false;
            db.Entry(pIV).State = EntityState.Unchanged;
            db.Entry(pIV).Property("PIVPrinted").IsModified = true;
            db.SaveChanges();

            return RedirectToAction("PrintDetails");

Solution 4

Using the Razor view engine you can mark the entry as hidden:-

    <div class="form-group" style="visibility:hidden;height:0px;">
            @Html.EditorFor(model => model.CreationDate)
            @Html.ValidationMessageFor(model => model.CreationDate, "", new { @class = "text-danger" })
    </div>

Or just this which is simpler:-

    @Html.HiddenFor(model => model.CreationDate)

Solution 5

If you dont want use hidden in view you must load yor entity from db and add yor changes like

var olduser= db.Persons.FirstOrDefault(p => p.id = user.id);
olduser.Name=user.Name; 
olduser.Sex=user.Sex;
persons.SaveChanges();
Share:
37,156
qakmak
Author by

qakmak

Updated on November 28, 2020

Comments

  • qakmak
    qakmak over 3 years

    As you know, When we want to Modify a data, We will go to Edit page:

    public ActionResult EditAdmin(int UserId)
    { 
            User user = persons.Users.Find(id);
            return View(user);
    }
    

    Then We submit it on the Edit Page, it will Modify:

    public ActionResult EditAdmin(User user)
    { 
            persons.Entry(user).State = EntityState.Modified;
            persons.SaveChanges();
    }
    

    But the problem is , I have alot of field don't need be modify:

    public class User{
        public int UserId {get; set;} // do not need modify
        public int Password {get; set;} // do not need modify
        public string Name {get; set;}
        public bool Sex {get; set;}
        public DateTime AddTime {get; set;} // do not need modify
    }
    

    Obviously, I can't display some field on my edit page use Hidden, because I don't want it display on UI. but when submit, I still need it still keep the original value. So Is there any good idea for it? Thanks

    Update1:

    Why I can't use like

    entry.Property(e => e.Password).IsModified = false;
    

    link: https://stackoverflow.com/a/18004476/1900498

    But It will display :

    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

  • Rhumborl
    Rhumborl over 9 years
    do you even need to set EntityState.Modified? The EF proxy should handle this
  • Kris Vandermotten
    Kris Vandermotten over 9 years
    This requires the action method to read and then write the row, which is two roundtrips to the database, where technically only one roundtrip is required. The select will read all "modifiable" fields to ensure the update sends only the ones actually modified. In fact, if your entity contains all columns in the table, you read them all, not just the "modifiable" ones. On the other hand, with one roundtrip you indeed don't know which fields were modified, so the update statement will send all "modifiable" columns to the database. Question is: which is worse?
  • qakmak
    qakmak over 9 years
    Why use x.FirstOrDefault() not x.Find()?
  • StuartLC
    StuartLC over 9 years
    @qakmak Yes, you can use Find, if you are confident that there is no chance you have a stale context. Kris - yes, I was assuming a need for an optimistic concurrency check, and also to ensure that a browser user didn't hack the JSON / POST and supply updated values for Id, Password etc. I guess an optimal solution would be UPDATE Person SET Name = {NewName}, Sex = {NewSec} WHERE ID = {OldId} AND LastUpdateTimeStamp={LastUpdateTimeStamp} and then throw an OptimisticConcurrencyException if the rows updated was zero, but thisn't very ORMish.
  • yazanpro
    yazanpro about 6 years
    Well you overlooked the crucial part. How do you get id in the post method?
  • Ric .Net
    Ric .Net about 6 years
    @yazanpro Yes, that was a bug. Edited the answer. Funny nobody else saw this in 3 years. You probably want to put the Id field in the UserViewModel in a hidden input in your razor view
  • yazanpro
    yazanpro about 6 years
    Thanks for addressing this. However, this way we're back to the original issue which is the need to "hide" certain properties from getting tampered with by the client. If you rely on the model like you did here, the user can modify the hidden field (the user id) in JavaScript and can cause an update to a different user. The way I worked around this is by using TempData to store the ID. The good thing about TempData is that is lasts between requests. I'm not sure if that's the best way though.
  • Ric .Net
    Ric .Net about 6 years
    @yazanpro The OP says nothing about tampering. The question is about not modifying data that should not be modified. This answer solves this, because only the properties that can be modified are modified. Changing the question to a security issue requires a total different answer. I have an answer for that also, not involving TempData. If you need info about this, create a new question and tag me
  • yazanpro
    yazanpro about 6 years
    You're right. The OP doesn't mention security. I apparently missed the point behind the question.
  • Don Gossett
    Don Gossett almost 6 years
    This solution worked for me and seemed like the simplest approach.
  • Jamie
    Jamie over 5 years
    This worked for me too, but how do I show the date on my page? I don't want it hidden because the user will want to know when the request was originally submitted - in my scenario. Thank you