Have you found yourself using ASP.NET MVC quite merrily building views and controllers and master/detail forms with 1-1 objects from your database to your view and now you’ve hit a hairy case which has ruined everything when you have a child and/or child collection object you also need to update on the form (or multiple of each one!) and have no idea how to tackle it? *breath* Well I was the same up until about an hour ago.
PS. If you just want to know how to bind a collection only and return that to your controller action, check my other post on complex model binding.
Well it appears you have to use the FormCollection object and a tweak on the UpdateModel() method in your save/update action. So if you are using model binders, toss that out the door, you can still use it for insert, but just not for update. This erked me because I am a big fan of model binders, and of course was trying to get some sort of “multiple model binding” solution online to no avail. However, now I have seen and implemented this approach, I am reasonably happy with it to the point I am comfortable not using a model binder in this scenario. If the community has any better approaches to this conundrum, please don’t hesitate to post on this article for myself and others.
SHOW ME THE CODE:
In your view:
<%using (Html.BeginForm(c => c.Save(ViewData.Model.User.ID, null, null), FormMethod.Post))
{ %>
<%= Html.TextBox("User.Username") %>
<%= Html.TextBox("User.Contact.FirstName") %>
<%= Html.CheckBox("User.Contact.Addresses[0].Primary")%>
<%= Html.CheckBox("User.Contact.Addresses[1].Primary")%>
...
<% } %>
In your controller action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(int id, FormCollection collection)
{
User user = null;
if (id == 0)
{
user = new User();
UpdateModel(user, "User");
user.Contact = new Contact();
UpdateModel(user.Contact, "User.Contact");
user.Contact.Addresses = new EntitySet<Address>();
UpdateModel(user.Contact.Addresses, "User.Contact.Addresses");
}
else
{
// get current user object from DB, however you normally do this is fine.
user = userRepository.GetById(id);
UpdateModel(user, "User");
UpdateModel(user.Contact, "User.Contact");
UpdateModel(user.Contact.Addresses, "User.Contact.Addresses");
}
// at this point, model "user" and children would have been updated.
}
...
Firstly, the above is just a simple example demonstrating a mixture of the flexibility in this method, whereby you either have a single entity, child entity or entity collections. You can use this for a grid, or just complex detail forms or whatever. While we’re speaking of grids, for an awesome strongly-typed grid control for MVC (yes it’s a control, and yes a control you might actually want to use in MVC), check out the one over on the MVCContrib site. The first argument of the UpdateModel() command describes which model to update and the second argument describes the prefix to search for on form values for the mapping.
The above is obviously an example in context of “user”, but this could be applied to your real-world object with ease.
Enjoy.
3 Comments
Fantastic article! And quite timely; I’ve been struggling with this myself and am eager to try this out. One question, however. Is your code sample using the MVC Futures assembly? I wasn’t aware you could pass a lambda expression into the BeginForm helper (very nice). Thanks!
I took a look at the Article but cannot figure out how to Update an child object that is an List does anybody know how to fix this problem?
And what if i have a CustomList like Telephones which have multiple Telephone objects in it?
How to fix this. I hope some1 can help me on this
This doesnt work right for me.
When i update the model, in the DB it creates new childs with the new valor and the older childs gets its parent ID set to null, but they still exist in the DB.
Post a Comment