简体   繁体   中英

MVC Passing a Complex Object to the controller for saving

I am writing a web page with MVC and Entity Framework. I have an order with line items attached and want to return a complex object to the controller for processing.

I have now included all the code.

My view :

@model BCMManci.ViewModels.OrderCreateGroup

@{
    ViewBag.Title = "Create";
}
<h2>New Order</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <h4>@Html.DisplayFor(model => model.Order.Customer.FullName)</h4>

    <table>
        <tr>
            <td><b>Order Date:</b> @Html.DisplayFor(model => model.Order.OrderDate)</td>
            <td><b>Status:</b> @Html.DisplayFor(model => model.Order.OrderStatus.OrderStatusName)</td>
        </tr>
        <tr>
            <td colspan="2">
                <b>Notes</b>
                @Html.EditorFor(model => model.Order.Notes, new { htmlAttributes = new { @class = "form-control" } })
            </td>
        </tr>
    </table>
        @Html.ValidationMessageFor(model => model.Order.Notes, "", new { @class = "text-danger" })
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })


        <table class="table table-striped table-hover">
            <thead>
                <tr>
                    <td>Name</td>
                    <td>Price</td>
                    <td>Discount</td>
                    <td>Total</td>
                    <td>Quantity</td>
                </tr>
            </thead>
            <tbody>
                @foreach (var product in Model.ProductWithPrices)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => product.ProductName)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => product.SellingPrice)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => product.DiscountPrice)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => product.TotalPrice)
                        </td>
                        <td>
                            @Html.EditorFor(modelItem => product.Quantity, new { htmlAttributes = new { @class = "form-control" } })
                        </td>
                    </tr>
                }
            </tbody>
        </table>

        <input type="submit" value="Create" class="btn btn-default" />
}
<div class="btn btn-danger">
    @Html.ActionLink("Cancel", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

}

Controller :

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "Order,ProductWithPrices,Order.Note,product.Quantity")] OrderCreateGroup order)
    {
        try
        {
            if (ModelState.IsValid)
            {
                db.Orders.Add(order.Order);

                foreach (var orderItem in order.ProductWithPrices.Select(item => new OrderItem
                {
                    OrderId = order.Order.OrderId,
                    ProductId = item.ProductId,
                    Quantity = item.Quantity,
                    ItemPrice = item.SellingPrice,
                    ItemDiscount = item.DiscountPrice,
                    ItemTotal = item.TotalPrice
                }))
                {
                    db.OrderItems.Add(orderItem);
                }
                db.SaveChanges();
                return RedirectToAction("ConfirmOrder", new {id = order.Order.OrderId});
            }
        }
        catch (DataException /* dex */)
        {
            //TODO: Log the error (uncomment dex variable name and add a line here to write a log.
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
        }
        ViewBag.Products = db.Products.Where(model => model.IsActive == true);

        PopulateDropdownLists();
        return View(order);
    }

Data Source :

public class OrderCreateGroup
{
    public OrderCreateGroup()
    {
        ProductWithPrices = new List<ProductWithPrice>();
    }

    public Order Order { get; set; }
    public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}

public class ProductWithPrice : Product
{
    public decimal SellingPrice { get; set; }
    public decimal DiscountPrice { get; set; }

    public int Quantity { get; set; }

    public decimal TotalPrice { get; set; }
}

However, the values that are entered on the form are not being passed, through. So I can't access them in the controller. The 'productWithPrices' collection is null although there is Data in it on the web page.

I have tried making it asyc and also tried changing the ActionLink button like below but it didn't get to the controller.

@Html.ActionLink("Create", "Create", "Orders", new { orderCreateGoup = Model }, null)

This is the controller but it now doesn't make sense as the parameter passed in the datasource for the page.

public ActionResult Create(OrderCreateGroup orderCreateGoup)

Please, can you give me direction on the best way of doing this?

In your OrderCreateGroup class initialize the collection to an empty list.

public class OrderCreateGroup
{
    public OrderCreateGroup()
    {
       ProductWithPrices = new List<ProductWithPrice>();
    }
    public Order Order { get; set; }
    public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}

You'll need to add @Html.HiddenFor(m => m.SellingPrice) and similarly for other bound fields that are using DisplayFor if you want to post them back to the controller.

Note: For your benefit, try to have a look at the generated HTML code when your page is rendered in the browser and see what tags are generated inside the <form> tag with a name attribute.

make sure you bind the appropriate property from the complex object, like the following:

@model  BCMManci.ViewModels.OrderCreateGroup

...
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">


        ...
        <div class="form-group">
            @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.OrderCreateGroup.Order.Quantity, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.OrderCreateGroup.Order.Quantity, "", new { @class = "text-danger" })
            </div>
        </div>



        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Note :model.OrderCreateGroup.Order.Quantity would be one the your order's property. hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM