实体框架核心中具有多对多关系的CRUD

时间:2020-09-18 11:34:19

标签: c# asp.net-core entity-framework-core

我有两个模型和一个联接表。 我想使用相同的视图来编辑和创建新的采购订单,同时以相同的形式添加商品。

PurchaseOrder模型:

public class PurchaseOrder
{
    public int ID { get; set; }

    [Required]
    public string Requester { get; set; }

    public int WorkOrder { get; set; }

    [Required]
    public string WorkSite { get; set; }

    public string Equipment { get; set; }

    public string Operator { get; set; }

    public string Remarks { get; set; }

    public ICollection<PurchaseOrderItem> Items { get; set; }
}

项目模型:

public class Item
    {
        public int ID { get; set; }

        public string PartNumber { get; set; }
    [Required]
    public string Name { get; set; }

    public string Description { get; set; }

    [Required]
    public int Quantity { get; set; }

    public string Remarks { get; set; }

    public ICollection<PurchaseOrderItem> PurchaseOrders { get; set; }
}

加入表实体

    public class PurchaseOrderItem
{
    public int PurchaseOrderID { get; set; }
    public int ItemID { get; set; }
    public PurchaseOrder PurchaseOrder { get; set; }
    public Item Item { get; set; }
}

PurchaseOrdersController编辑:

public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var purchaseOrder = await _context.PurchaseOrders
                .Include(x => x.Items)
                    .ThenInclude(x => x.Item)
                .Where(x => x.ID == id)
                .AsNoTracking()
                .SingleOrDefaultAsync();

            if (purchaseOrder == null)
            {
                return NotFound();
            }

            return View(purchaseOrder);
        }

编辑帖子方法:

[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, PurchaseOrder order)
        {
            if (id != order.ID)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    var po = _context.PurchaseOrders.FirstOrDefault(i => i.ID == order.ID);
                    po.Requester = order.Requester;
                    po.WorkOrder = order.WorkOrder;
                    po.WorkSite = order.WorkSite;
                    po.Equipment = order.Equipment;
                    po.Operator = order.Operator;
                    po.Remarks = order.Remarks;

                    _context.Update(po);

                    

                    foreach (var i in order.Items)
                    {
                        var item = _context.Items.FirstOrDefault(n => n.ID == i.Item.ID);
                        item.PartNumber = i.Item.PartNumber;
                        item.Name = i.Item.Name;
                        item.Description = i.Item.Description;
                        item.Quantity = i.Item.Quantity;
                        item.Remarks = i.Item.Remarks;

                        _context.Update(item);
                    }

                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {

                    if (!PurchaseOrderExists(order.ID))
                    {
                        return NotFound();

                    }

                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }

            return View(order);

        }

编辑视图

@model OrderTrackingApp.Models.PurchaseOrder

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>PurchaseOrder</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="ID" />
            <div class="form-group">
                <label asp-for="Requester" class="control-label"></label>
                <input asp-for="Requester" class="form-control" />
                <span asp-validation-for="Requester" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="WorkOrder" class="control-label"></label>
                <input asp-for="WorkOrder" class="form-control" />
                <span asp-validation-for="WorkOrder" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="WorkSite" class="control-label"></label>
                <input asp-for="WorkSite" class="form-control" />
                <span asp-validation-for="WorkSite" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Equipment" class="control-label"></label>
                <input asp-for="Equipment" class="form-control" />
                <span asp-validation-for="Equipment" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Operator" class="control-label"></label>
                <input asp-for="Operator" class="form-control" />
                <span asp-validation-for="Operator" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Remarks" class="control-label"></label>
                <input asp-for="Remarks" class="form-control" />
                <span asp-validation-for="Remarks" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label class="control-label">Order Items</label>
                <table>
                    <tbody>
                        @{ int i = 0;}
                        <tr>
                            @foreach (var OrderItem in Model.Items)
                            {
                                <td>
                                    <input type="hidden" value="OrderItem[@i].ItemID" asp-for="@OrderItem.ItemID"
                                           class="form-control" />
                                    <input type="text" value="OrderItem[@i].Item.PartNumber" asp-for="@OrderItem.Item.PartNumber" class="form-control" />
                                    <input type="text" value="OrderItem[@i].Item.Name" asp-for="@OrderItem.Item.Name" />
                                </td>
                                i++;
                            }
                        </tr>
                    </tbody>
                </table>
            </div>

            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>


        </form>

    </div>
</div>

    


<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

我目前在编辑时遇到两个问题:

  • 该项目的标签填充如下:OrderItem [0] .Item.Name代替Value
  • 当代码到达foreachloop来迭代项目时,它将引发空异常。

2 个答案:

答案 0 :(得分:0)

您仅获得关于新添加的子项的名称,没有ID。并且未初始化子数据的关系表ID的返回值中返回的空值。

您可以按照适用性通过以下两种方式解决此问题:

  • 直接从视图添加子行并更新模型中的ID,因此您 数据中将始终具有ID,并且您不需要面部null ID 问题。

  • 或者,您可能需要先添加子表的新值 然后在保存更改之前手动在关系数据中使用新的ID。

答案 1 :(得分:0)

问题是模型绑定,它基于name属性。更改如下代码:

@{ int i = 0;}
<tr>
    @foreach (var OrderItem in Model.Items)
    {
        <td>
            <input type="hidden" name="Items[@i].Item.ID" asp-for="@OrderItem.Item.ID"
                    class="form-control" />
            <input type="text" name="Items[@i].Item.PartNumber" asp-for="@OrderItem.Item.PartNumber" class="form-control" />
            <input type="text" name="Items[@i].Item.Name" asp-for="@OrderItem.Item.Name" class="form-control" />
        </td>
        i++;
    }
</tr>