MVC.Net binding complex models?

2020-08-01 05:22发布

问题:

I have the following code, with an existing customer. I need to create a form that created an Order, and pass it to my Controller.

I tried changing my model type on that page to Order instead of Customer, but then I'm gonna have to pass the Order object as well, or at least the OrderId.

Models

public class Customer
{
   public int Id { set; get; }
   public string FirstName { set; get; }
   public string LastName { set; get; }
   public List<Order> Orders { get; set;}
}

public class Order
{
   public int Id { set; get; }
   public string ItemName { set; get; }
   public DateTime SomeDate { set; get; }
}

Controller

public class OrderController : Controller
{
   [HttpPost]
   public Create ActionResult(Customer customer)
   {
      // Customer doesn't have the values that it suppose to have
      // All fields including the array of orders are null
      customerStorage.UpdateOrders(customer);

      return ("ItemListPartial", customer.orders);
   }
}

View

@model Company.Application.Model.Customer;

@using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "result" }))
{
    // How can I bind this to Order object ?
    // I can't define model as Order, because then I need to pass Customer Separately
    @Html.TextBoxFor(o => o.Orders[0].ItemName)
    @Html.TextBoxFor(o => o.Orders[0].SomeDate)
    <input type="submit" value="Add" />
}

回答1:

I suppose you're looking for what this blog article describes: ASP.NET MVC Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

Quote from the blog:

If the signature looks like this:

public ActionResult Blah(IDictionary<string, Company> stocks) {
  // ...
}

And we are given this in HTML:

<input type="text" name="stocks[0].Key" value="MSFT" />
<input type="text" name="stocks[0].Value.CompanyName" value="Microsoft Corporation" />
<input type="text" name="stocks[0].Value.Industry" value="Computer Software" />
<input type="text" name="stocks[1].Key" value="AAPL" />
<input type="text" name="stocks[1].Value.CompanyName" value="Apple, Inc." />
<input type="text" name="stocks[1].Value.Industry" value="Consumer Devices" />

Which like this:

stocks[0].Key = "MSFT"
stocks[0].Value.CompanyName = "Microsoft Corporation"
stocks[0].Value.Industry = "Computer Software"
stocks[1].Key = "AAPL"
stocks[1].Value.CompanyName = "Apple, Inc."
stocks[1].Value.Industry = "Consumer Devices"

Then it will be just as if we had written:

stocks = new Dictionary<string, Company>() {
  { "MSFT", new Company() { CompanyName = "Microsoft Corporation", Industry = "Computer Software" } },
  { "AAPL", new Company() { CompanyName = "Apple, Inc.", Industry = "Consumer Devices" } }
};


回答2:

This IMO is how you should be handling this:

Pass customerID in your viewbag if you're really not wanting to make a viewmodel (p.s. It is ok to make a viewmodel!)

public class OrderController : Controller
{
   public ActionResult Create(int customerID)
   {
      ViewBag.CustomerID = customerID
      Order ord = new Order(o);
      return View(ord);
   }
}

your post method:

[HttpPost]
public ActionResult Create(int CustomerID, Order order)
{
  //create your order
}

your cshtml

@model Company.Application.Model.Order;

@using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "result" }))
{
    @Html.TextBoxFor(o => o.ItemName)
    @Html.TextBoxFor(o => o.SomeDate)
    @Html.Hidden("CustomerID",ViewBag.CustomerID)
    <input type="submit" value="Add" />
}