views:

549

answers:

2

I'm designing forms in my ASP.NET MVC application that will receive objects. Here's what a typical edit action looks like:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, Person person)
    {
        peopleService.SavePerson(person);
        return Redirect("~/People/Index");
    }

The SavePerson call in the service does this:

    public void SavePerson(Person person)
    {
        _peopleRepository.SavePerson(person);
    }

And the SavePerson call in the repository does this:

    public void SavePerson(Person person)
    {
        using (var dc = new SIGAPDataContext())
        {
            if (person.IsNew)
            {
                dc.People.InsertOnSubmit(person);
            }
            else
            {
                dc.People.Attach(person, true);
            }

            dc.SubmitChanges();
        }
    }

Now, this works well when I create the new record. However, when I update it without all the form elements, it nulls other fields. For instance, my Person model has a NationalityID property that is nulled if it doesn't show on the edit form.

What's the best practice to make the model update with just the fields that come from the form? Do I have to get the record from the database first and update it's properties manually like:

Person persistedPerson = peopleService.GetPerson(person.ID);
persistedPerson.Name = person.Name;
persistedPerson.DateOfBirth = person.DateOfBirth
// etc...

Or is there any other, cleaner way to do this?

+2  A: 

Stephen Walther just posted an article describing this very thing in ASP.NET MVC. I would recommend you actually create your own set of DTO's and business objects on top of LINQ to SQL and treat LINQ to SQL as a language-integrated object database due to the gross complexities introduced by managing the DataContext, which according to Pro LINQ, should be kept alive as little as possible by design.

If you are going to use your LINQ to SQL entities as your DTO's, you should get the entity first, detach it, update it, re-attach it, then submit it.

Ryan Riley
+1  A: 

In your controller, retrieve the existing person from the repository, then use UpdateModel/TryUpdateModel and pass in a whitelist of properties that you want to be updated. This would use the ValueProvider on the controller so there is no need to take the Person object in the action parameter list.

public ActionResult Edit( int id )
{
      Person person = peopleService.GetPerson(id);
      UpdateModel(person,new string[] { list of properties to update } );
      peopleService.SavePerson(person);

      ...
}
tvanfosson
Now I only need how to use UpdateModel to work with nested entities on my forms. Thanks a lot!
changelog
Update them as submodels using a different whitelist and prefix, if necessary.
tvanfosson
See my answer to this question: http://stackoverflow.com/questions/594412/model-binding-of-nested-properties-in-asp-net-mvc/594458#594458
tvanfosson