Редактирование и сохранение сложных объектов

Допустим, у вас есть следующий объект:

public class Address
{
  public String Line1 { get; set; }
  public String Line2 { get; set; }
  public String City { get; set; }
  public String State { get; set; }
  public String ZipCode { get; set; }

  public Address()
  {
  }
}

public class Contact
{
  public String FirstName { get; set; }
  public String LastName { get; set; }
  public String Telephone { get; set; }

  public Address BillingAddress { get; set; }
  public List<Address> ShippingAddresses { get; set; }

  public Contact()
  {
    // Assume anything that _could_ be null wouldn't be. I'm excluding
    // most "typical" error checking just to keep the examples simple
    this.BillingAddress = new Address();
    this.ShippingAddresses = new List<Address>();
  }
}

Предположим, что свойства украшены [Required], [Display] и другими атрибутами.

Затем мой контроллер (упрощенный для демонстрации):

public ActionResult Edit(String id)
{
  Contact contact = ContactManager.FindByID(id);
  return View(model: contact);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Contact contact)
{
  if (ModelState.IsValid) //always fails
  {
    ContactManager.Save(contact);
    return RedirectToAction("Saved");
  }
  return View(model: contact);
}

Я постоянно вижу демонстрации редактирования объекта в MVC, но они постоянно разбивают коллекции объекта на свои собственные формы (например, редактирование контакта, затем редактирование конкретного адреса из контакта). С другой стороны, я пытаюсь редактировать всю эту информацию на одной странице и не имею успеха. Например:

@model Contact

// simplified for brevity
@using (Html.BeginForm())
{
  @Html.LabelFor(x => x.FirstName): @Html.EditorFor(x => x.FirstName)
  @Html.LabelFor(x => x.LastName): @Html.EditorFor(x => x.LastName)
  @Html.LabelFor(x => x.Telephone): @Html.EditorFor(x => x.Telephone)

  <div>
    @Html.LabelFor(x => x.BillingAddress.Line1): @Html.EditorFor(x => x.BillingAddress.Line1)
    @Html.LabelFor(x => x.BillingAddress.Line2): @Html.EditorFor(x => x.BillingAddress.Line2)
    @Html.LabelFor(x => x.BillingAddress.City): @Html.EditorFor(x => x.BillingAddress.City)
    @Html.LabelFor(x => x.BillingAddress.State): @Html.EditorFor(x => x.BillingAddress.State)
    @Html.LabelFor(x => x.BillingAddress.ZipCode): @Html.EditorFor(x => x.BillingAddress.ZipCode)
  </div>

  <div>
  @foreach (Address addr in Model.ShippingAddresses)
  {
    <div>
      @Html.LabelFor(x => addr.Line1): @Html.EditorFor(x => addr.Line1)
      @Html.LabelFor(x => addr.Line2): @Html.EditorFor(x => addr.Line2)
      @Html.LabelFor(x => addr.City): @Html.EditorFor(x => addr.City)
      @Html.LabelFor(x => addr.State): @Html.EditorFor(x => addr.State)
      @Html.LabelFor(x => addr.ZipCode): @Html.EditorFor(x => addr.ZipCode)
    </div>
  }
  </div>
}

Проблема в том, что ModelState.IsValid никогда не проходит, когда я пытаюсь сохранить информацию обратно. Есть ли хитрость, как это сделать, или это просто вне сферы MVC? Я хотел бы взять объект типа Contact и выгрузить всю информацию на одну страницу для редактирования, и чтобы она успешно сохранялась, но я не могу заставить его работать. (Мой следующий шаг - подключить ajax, чтобы можно было динамически добавлять/удалять "ShipingAddresses" на этой странице, но мне нужно, чтобы сначала работало сохранение - K.I.S.S.)

Проблемы:

  • ModelState. IsValid почти всегда false
  • Элементы формы для элементов коллекции часто имеют одинаковые имена, поэтому в этом демо каждая Line1 в коллекции ShippingAddresses сбрасывается на страницу как name="addr_Line1" вместо чего-то вроде ShippingAddresses[0]_Line1, как я ожидал.
7
задан Brad Christie 28 January 2012 в 15:57
поделиться