Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating Parent/Child Records with model binders in ASP.Net MVC

I have modified the Nerd Dinner application to allow editing of child records by adding the following code to the DinnerForm.ascx

  <p>
    <%int i = 0;
   foreach (NerdDinner.Models.RSVP rsvp in this.Model.Dinner.RSVPs)
       { %>

        <%= Html.Hidden("Dinner.RSVPs[" + i + "].RsvpID", rsvp.RsvpID)%>
        <%= Html.Hidden("Dinner.RSVPs[" + i + "].DinnerID", rsvp.DinnerID)%>
        <%= Html.TextBox("Dinner.RSVPs[" + i + "].AttendeeName", rsvp.AttendeeName)%>
    <% i += 1;
   } %>
    </p>

it is rendering this:

<p>
    <input id="Dinner_RSVPs[0]_RsvpID" name="Dinner.RSVPs[0].RsvpID" type="hidden" value="36" />
        <input id="Dinner_RSVPs[0]_DinnerID" name="Dinner.RSVPs[0].DinnerID" type="hidden" value="63" />
        <input id="Dinner_RSVPs[0]_AttendeeName" name="Dinner.RSVPs[0].AttendeeName" type="text" value="kp" />
    <input id="Dinner_RSVPs[1]_RsvpID" name="Dinner.RSVPs[1].RsvpID" type="hidden" value="37" />
        <input id="Dinner_RSVPs[1]_DinnerID" name="Dinner.RSVPs[1].DinnerID" type="hidden" value="63" />
        <input id="Dinner_RSVPs[1]_AttendeeName" name="Dinner.RSVPs[1].AttendeeName" type="text" value="jim" />

    </p>   

I have not modified the DinnersControler's Post Edit Action method. The Parent dinner is getting updated as usual, but it appears the UpdateModel(dinner); is not seeing/updating the child RSVP records.

I have tried a few variations on rendering the child records so that the Model binders will see the collection, with no luck.

Is updating parent/child records in one shot by calling UpdateModel(Parent); possible with the current model binders?

like image 696
KP. Avatar asked Oct 14 '22 15:10

KP.


1 Answers

I haven't been able to do this myself.

I know that you can update a single child element, ie, Dinner.RSV automatically. I've never seen the ability to update a child enumerable, which would require the binding to know which property is the ID and look for it (ie, Dinner.RSVP.Where(r => r.RSVP_ID == input_id) and then update that). I don't know enough about custom binding to do something like that.

However, what I have done is to do a loop and specify the rsvp and the int as a prefix:

So you do:

UpdateModel("Dinner", Dinner);

to update the parent and then:

int i = 0;

foreach (var r in Dinner.RSVPs) {
  UpdateModel(r, "Dinner.RSVPs[" + i++ + "]");
}

Not quite as clean, but it works well for me. It might take a bit more effort to build in validation, though (you want to validate all at the same time, and make sure you don't jump back to the view on the first RSVP with an error).

EDIT: Fixed the code to reflect the OP's solution, including a bug in my parameter order. With that being said, I'm more comfortable using the RSVP.ID property than a running integer. As long as you know that Dinner.RSVPs will be the same on the POST as the GET (I'm confident of this in my code), then using the RSVP.ID will work. Should RSVPs be different, then only those present on both will get updated. However, using the sequential int could potentially cause the wrong object to be updated.

Hope that helps, James

like image 127
James S Avatar answered Oct 20 '22 15:10

James S