简体   繁体   中英

How to Insert to Master-detail tables in ASP.NET MVC 5

I have Orders table and OrderDetails table in DB. With Entity Framework 6 I have obtained a model so I have classes generated from it. I also generated controllers and views from the Orders table.

Orders
folio (PK)
date
customer (FK)

OrdersDetail
folio (FK) -- to the Orders table
product (FK)
price
quantity 

The generated Create Post action is the following:

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "folio,date,customer")] Orders order)
        {

            if (ModelState.IsValid)
            {
                db.Orders.Add(order);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            ViewBag.cliente = new SelectList(db.CATCTES, "COD_CTE", "NOM_CTE", order.cliente);

            return View(order);
        }

That's okay, but I would need to Insert to the other entity/table too! I already changed the Create.cshtml form, with the fields required for Orders table and including some kind of grid for OrdersDetail. Each row is a new entry for OrdersDetail table.

在此输入图像描述

The problem, is I don't know how to properly save to the other table in the Create action at Orders controller. If this is not the right approach, tell me your comments.

Another concern is about POSTing, How should I name the inputs to be properly grouped and use submitted values at controller? Each row is generated by this script when I click a "+" button on the form:

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script>
        function add_row() {
            var detalle = $('#detalle');
            var newRow = '<tr>' + 
                            '<td data-title="Product">' +
                              '<div class="input-group">' +
                                '<span class="input-group-addon"></span>' +
                                  '<input class="form-control" type="number" aria-label="Product" name="detail_array[].product" step="0.001" min="0.000" onchange="cambiar_importe(this)" required="true">' +
                              '</div>' +
                            '</td>' +
                            '<td data-title="Price" >' +
                              '<div class="input-group">' +
                                '<span class="input-group-addon">$</span>' +
                                  '<input type="number" class="form-control" aria-label="Price" name="detail_array[].price" onchange="cambiar_importe(this)" step="0.001" min="0.000" required="true">' +
                              '</div>' +
                            '</td>' +
                            '<td data-title="Quantity">' +
                              '<div class="input-group">' +
                                '<span class="input-group-addon">$</span>' +
                                  '<input type="text" class="importe form-control" aria-label="Quantity" name="detail_array[].quantity" step="0.001" min="0.000" readonly="true" >' +
                              '</div>' +
                            '</td>' +
                            '<td data-title=""><button type="button" class="btn btn-danger btn-sm" onclick="borrar_renglon(this)">Cancelar</button></td>' +
                          '</tr>';

            detalle.append(newRow);
        }

    </script>
}

I think you should use Ajax.

In your view you have the grid section, each time you add a record you have to post the values to the server using Ajax post form:

@using (Ajax.BeginForm("AddDetails", new AjaxOptions { UpdateTargetId = "gridContainerElementId" }))
{
  @Html.HiddenFor(m => m.folio)
  @Html.HiddenFor(m => m.product)
  @Html.TextBox(m => m.price)
  @Html.TextBox(m => m.quantity)
  <input type = "submit" value = "Save"/>
}

Note: put your grid in 'gridContainerElementId' div like:

<div id="gridContainerElementId">
  @Html.Action("DetailsGridPartial", new { OrderId = Model.folio })
</div>

In your controller

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddDetails(OrdersDetail orderDetails)
{
   if (ModelState.IsValid)
   {
      db.OrdersDetail.Add(orderDetails);
      db.SaveChanges();

      return RedirectToAction("DetailsGridPartial", new { OrderId =  orderDetails.folio });
   }
   return View(order);
}

public ActionResult DetailsGridPartial(int OrderId)
{
      var orderDetails = db.OrdersDetail.Where(w => w.folio == OrderId);
      return PartialView(orderDetails);
}

You need to create new view to show the grid:

@model IEnumerable<OrdersDetail>
@Html.YourHelper.Grid(model).Html() @*or however you build the grid*@

In this case you will not need to fill the grid manually by the new record, the grid will be refreshed automatically.

I hope this helps

In your Create Post action method, you need to handle disconnected approach when working with web technologies like MVC, Web API, WCF etc.

Orders should contain list of OrderDetails, when its read in action parameter. Look for if its editing or addition and change Entity state accordingly to Added or Modified.

This usually happens because in web apps EF doesn't deal with entity tracking. Please refer this link EF disconnected apps . Apply the scenario which are similar to your's.

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