title: Better Way To Edit A View Model in MVC
body: <p>I actually came up with a working example of how to display (GET) and edit (POST) a view model consisting of three models in MVC.  However, my MVC skills are limited and I was looking for suggestions on "the right way" I should be doing this.
  The part in question is that I'm sending the form fields back individually rather than to a view model, which is something I couldn't figure out how to do.</p>
  
  <p>Here are my models</p>
  
  <p><strong>Name</strong></p>
  
  <pre><code>public partial class Name
  {
      public Name()
      {
          this.Addresses = new HashSet&lt;Address&gt;();
          this.Emails = new HashSet&lt;Email&gt;();
      }
  
      public int ID { get; set; }
      public string FIRST_NAME { get; set; }
      public string LAST_NAME { get; set; }
  
      public virtual ICollection&lt;Address&gt; Addresses { get; set; }
      public virtual ICollection&lt;Email&gt; Emails { get; set; }
  }
  </code></pre>
  
  <p><strong>Address</strong></p>
  
  <pre><code>public partial class Address
  {
      public int ADDRESS_ID { get; set; }
      public int NameID { get; set; }
      public string ADDRESS_1 { get; set; }
      public string CITY { get; set; }
      public string STATE { get; set; }
      public string ZIP { get; set; }
  
      public virtual Name Name { get; set; }
  }
  </code></pre>
  
  <p><strong>Email</strong></p>
  
  <pre><code>public partial class Email
  {
      public int EMAIL_ID { get; set; }
      public int NameID { get; set; }
      public string EMAIL { get; set; }
  
      public virtual Name Name { get; set; }
  }
  </code></pre>
  
  <p><strong>My View Model made up of all the fields from the three models.</strong></p>
  
  <pre><code>public class ContactFormViewModel
  {
      public int? ID { get; set; }
      public string FIRST_NAME { get; set; }
      public string LAST_NAME { get; set; }
      public string ADDRESS_1 { get; set; }
      public string CITY { get; set; }
      public string STATE { get; set; }
      public string ZIP { get; set; }
      public string EMAIL { get; set; }
  }
  </code></pre>
  
  <p><strong>The GET method of the Edit page (in the Controller)</strong></p>
  
  <pre><code>    // GET: Names/Edit/5
      //The GET method takes the id from the URL and passes it into the query to return data for the specific record
      public ActionResult Edit(int id)
      {
          //This query is an outer join of the Name, Address and Email models/tables
          var query = from n in db.Names
                      join a in db.Addresses
                      on n.ID equals a.NameID into na
                      from a in na.DefaultIfEmpty()
                      join e in db.Emails
                      on n.ID equals e.NameID into ne
                      from e in ne.DefaultIfEmpty()
                      where n.ID == id
                      //Creates a new instance of the view model, populated with the query data
                      select new ContactFormViewModel
                      {
                          ID = id,
                          FIRST_NAME = n.FIRST_NAME,
                          LAST_NAME = n.LAST_NAME,
                          ADDRESS_1 = a.ADDRESS_1,
                          CITY = a.CITY,
                          STATE = a.STATE,
                          ZIP = a.ZIP,
                          EMAIL = e.EMAIL
                      };
  
          //Returns the query to the view
          return View(query);
      }
  </code></pre>
  
  <p><strong>The POST method of the Edit page (in the Controller)</strong></p>
  
  <pre><code>    // POST: Names/Edit/5
      [HttpPost]
      [ValidateAntiForgeryToken]
      //The POST method takes the individual form field data and passes it to queries that update all three models separately 
      public ActionResult Edit(int id, string FIRST_NAME, string LAST_NAME, string ADDRESS_1, string CITY, string STATE, string ZIP, string EMAIL)
      {
          if (ModelState.IsValid)
          {
              //Query the database for the row to be updated. 
              var queryN =
                  from n in db.Names
                  where n.ID == id
                  select n;
  
              var queryA =
                  from a in db.Addresses
                  where a.NameID == id
                  select a;
  
              var queryE =
                  from e in db.Emails
                  where e.NameID == id
                  select e;
  
              //Assign the form field data to the fields in the model 
              foreach (Name n in queryN)
              {
                  n.FIRST_NAME = FIRST_NAME;
                  n.LAST_NAME = LAST_NAME;
              }
  
              //If there are no address records, insert
              if (!queryA.Any())
              {
                  //New instance of Address
                  var address = new Address
                  {
                      NameID = id,
                      ADDRESS_1 = ADDRESS_1,
                      CITY = CITY,
                      STATE = STATE,
                      ZIP = ZIP
  
                  };
                  db.Addresses.Add(address);
              }
              //Else, if there are address records, then update
              else
              {
                  foreach (Address a in queryA)
                  {
                      a.ADDRESS_1 = ADDRESS_1;
                      a.CITY = CITY;
                      a.STATE = STATE;
                      a.ZIP = ZIP;
                  }
              }
  
              //If there are no email records, insert
              if (!queryE.Any())
              {
                  //New instance of Email
                  var email = new Email
                  {
                      NameID = id,
                      EMAIL = EMAIL
                  };
                  db.Emails.Add(email);
              }
              //Else, if there are email records, then update
              else
              {
                  foreach (Email e in queryE)
                  {
                      e.EMAIL = EMAIL;
                  }
              }
  
  
              //// Submit the changes to the database. 
              try
              {
                  db.SaveChanges();
              }
              catch (Exception ex)
              {
                  Console.WriteLine(ex);
                  // Provide for exceptions.
              }
  
          }
          return RedirectToAction("Index");
      }
  </code></pre>
  
  <p><strong>The View</strong></p>
  
  <pre><code>@model IQueryable&lt;MDTestApplication.ViewModel.ContactFormViewModel&gt;
  
  @{
      ViewBag.Title = "Edit";
  }
  
  &lt;h2&gt;Edit&lt;/h2&gt;
  
  @using (Html.BeginForm())
  {
      @Html.AntiForgeryToken()
  
      &lt;div class="form-horizontal"&gt;
          &lt;h4&gt;Name&lt;/h4&gt;
          &lt;hr /&gt;
  
          @*Uses foreach loop to get all field data from the view model*@
          @foreach (var item in Model)
          {
              @Html.ValidationSummary(true, "", new { @class = "text-danger" })
              @Html.HiddenFor(modelItem =&gt; item.ID)
  
              &lt;div class="form-group"&gt;
                  @Html.LabelFor(modelItem =&gt; item.FIRST_NAME, htmlAttributes: new { @class = "control-label col-md-2" })
                  &lt;div class="col-md-10"&gt;
                      @*Using razor syntax to output the value*@
                      @*Using form field 'Name' attribute for posting back to the controller*@
                      &lt;input type="text" name="FIRST_NAME" value="@item.FIRST_NAME" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.LAST_NAME, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="LAST_NAME" value="@item.LAST_NAME" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.ADDRESS_1, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="ADDRESS_1" value="@item.ADDRESS_1" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.CITY, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="CITY" value="@item.CITY" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.STATE, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="STATE" value="@item.STATE" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.ZIP, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="ZIP" value="@item.ZIP" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="form-group"&gt;
              @Html.LabelFor(modelItem =&gt; item.EMAIL, htmlAttributes: new { @class = "control-label col-md-2" })
              &lt;div class="col-md-10"&gt;
                  &lt;input type="text" name="EMAIL" value="@item.EMAIL" class="form-control" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
      }
          &lt;div class="form-group"&gt;
              &lt;div class="col-md-offset-2 col-md-10"&gt;
                  &lt;input type="submit" value="Save" class="btn btn-default" /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  }
  
  &lt;div&gt;
      @Html.ActionLink("Back to List", "Index")
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Here's additional insert and update code I added to Alex's answer below.  You would use this same setup for address and email. </p>
  
  <pre><code>foreach (var address in model.Addresses)
      {
          var addressToUpdate = name.Addresses.FirstOrDefault(a =&gt; AddressId== address.AddressId);
          if (addressToUpdate != default(Address))
          {
              // preform an update
              addressToUpdate.AddressId = address.AddressId;
              addressToUpdate.City = address.City;
              addressToUpdate.State = address.State;
              addressToUpdate.Zip = address.Zip;                           
          }
          else
          {
              //perform an insert
              var newAddress = new Address
              {
                  NameID = model.ID,
                  Address1 = address.Address1,
                  City = address.City,
                  State = address.State,
                  Zip = address.Zip
              };
              db.Addresses.Add(newAddress);
          }
      }
  </code></pre>