You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC C#中遍历并编辑勾选复选框的数据库实体记录

问题与修复方案:批量更新订单及关联库存

问题描述

刚接触MVC与Web开发,需要实现以下功能:在展示ProductOrders表记录的表单中,为每行添加复选框,勾选任意数量行后提交,遍历并更新这些行的多个字段,同时关联更新Products表的库存,必须通过ProductOrderID确保更新准确性。目前视图的foreach部分提示对象引用错误,附上原视图与控制器代码,寻求解决方法。


原视图代码

@model IEnumerable<AMS_ITAMSdb.Models.ProductOrder>
@using AMS_ITAMSdb.Models
@using AMS_ITAMSdb.Controllers

@{
    ViewBag.Title = "ReturnOrder";
}

@using (Html.BeginForm())
{
    <div class="title">
        <h4>Return Order</h4>
    </div>
    <p class="filter-section">
        <label class="filter-lbl1">Order #:&nbsp;</label>@Html.TextBox("orderNum", "", new { @class = "num" })<label class="lbl-txt">&nbsp;<i>(Type in order number here)</i></label>
        <input type="submit" value="Search" />&nbsp;
        <button type="button" onclick="location.href='@Url.Action("ReturnOrder")'">Reset</button>
    </p>
}
<table class="table">
    <tr>
        <th>
            Order #
        </th>
        <th>
            Product Code
        </th>
        <th>
            Qty Ordered
        </th>
        <th>
            Qty Available
        </th>
        <th>
            Return?
        </th>
        <th>
            New Qty Available
        </th>
    </tr>

    @foreach(var item in Model)
    {
        using(Html.BeginForm())
        { 
            <tr>
                <td>
                    @Html.HiddenFor(modelitem => item.ProductOrderID)
                    @Html.DisplayFor(modelitem => item.OrderID)
                </td>
                <td>
                    @Html.DisplayFor(modelitem => item.Product_Code)
                </td>
                <td>
                    @Html.DisplayFor(modelitem => item.Qty_Ordered)
                </td>
                <td>
                    @Html.DisplayFor(modelitem => item.Qty_Available)
                </td>
                <td class="checkbox">
                    <input type="checkbox" id="@item.Returned" name="checkRec" value="true" />
                </td>
                <td>
                </td>
            </tr>
        }
    }
</table><br /><br />
<div class="tbl-footer">
    @using(Html.BeginForm("ReturnedOrder", "ProductOrders", FormMethod.Post))
    {
        <input type="submit" class="button" />
    }
</div><br /><br />

原控制器代码

//GET: ProductOrders/ReturnOrder
public ActionResult ReturnOrder(string orderNum, ProductOrder productOrder)
{
    if (!String.IsNullOrEmpty(orderNum))
    {
        //Filter results based on OrderID entered in textbox
        var prod = db.ProductOrders.Where(x => x.OrderID.ToString() == orderNum);
        return View(prod.ToList());
    }
    else
    {
        var product = db.ProductOrders.OrderBy(x => x.OrderID).Where(x => x.Returned == null);
        return View(product.ToList());
    }
}

//POST: ProductOrders/ReturnedOrder/
[HttpPost]
public ActionResult ReturnedOrder(ProductOrder productOrder, bool checkRec = false)
{
    if (checkRec == true)
    {
        productOrder.Qty_Returned = productOrder.Qty_Returned;
        productOrder.Qty_Available = productOrder.Qty_Ordered + productOrder.Qty_Available;
        productOrder.Qty_On_Hand = productOrder.Qty_On_Hand - productOrder.Qty_Ordered;
        db.Entry(productOrder).State = EntityState.Modified;
        db.SaveChanges();

        Product product = db.Products.Where(x => x.ProductID == productOrder.ProductID).FirstOrDefault();
        product.Qty_Available = productOrder.Qty_Available;
        db.Entry(product).State = EntityState.Modified;
        db.SaveChanges();
    };                                            
    return View("ReturnOrder");
}

问题分析与修复步骤

1. 视图层核心问题修复

  • 解决对象引用错误:遍历Model前先判断是否为null,避免空引用
  • 统一表单结构:把整个表格包裹在提交表单内,取消每行单独的form,确保批量提交选中项
  • 修正复选框配置:将复选框name设为selectedOrderIds,value绑定item.ProductOrderID,提交时可获取所有选中的ID数组
  • 修正Hidden字段:手动生成hidden字段存储ProductOrderID,避免Html辅助器的命名问题

修改后的视图代码:

@model IEnumerable<AMS_ITAMSdb.Models.ProductOrder>
@using AMS_ITAMSdb.Models
@using AMS_ITAMSdb.Controllers

@{
    ViewBag.Title = "ReturnOrder";
}

@using (Html.BeginForm("ReturnOrder", "ProductOrders", FormMethod.Get))
{
    <div class="title">
        <h4>Return Order</h4>
    </div>
    <p class="filter-section">
        <label class="filter-lbl1">Order #:&nbsp;</label>@Html.TextBox("orderNum", "", new { @class = "num" })<label class="lbl-txt">&nbsp;<i>(Type in order number here)</i></label>
        <input type="submit" value="Search" />&nbsp;
        <button type="button" onclick="location.href='@Url.Action("ReturnOrder")'">Reset</button>
    </p>
}

<!-- 批量提交表单包裹整个表格 -->
@using (Html.BeginForm("ReturnedOrder", "ProductOrders", FormMethod.Post))
{
    <table class="table">
        <tr>
            <th>Order #</th>
            <th>Product Code</th>
            <th>Qty Ordered</th>
            <th>Qty Available</th>
            <th>Return?</th>
            <th>New Qty Available</th>
        </tr>

        <!-- 先判断Model是否为空,避免空引用错误 -->
        @if (Model != null && Model.Any())
        {
            foreach(var item in Model)
            {
                <tr>
                    <td>
                        <!-- 手动生成hidden字段,确保提交时能传递ProductOrderID -->
                        <input type="hidden" name="selectedOrderIds" value="@item.ProductOrderID" />
                        @Html.DisplayFor(modelitem => item.OrderID)
                    </td>
                    <td>@Html.DisplayFor(modelitem => item.Product_Code)</td>
                    <td>@Html.DisplayFor(modelitem => item.Qty_Ordered)</td>
                    <td>@Html.DisplayFor(modelitem => item.Qty_Available)</td>
                    <td class="checkbox">
                        <!-- 复选框name统一为selectedOrderIds,value为ProductOrderID -->
                        <input type="checkbox" name="selectedOrderIds" value="@item.ProductOrderID" />
                    </td>
                    <td>
                        <!-- 可显示计算后的新库存,方便预览 -->
                        @(item.Qty_Available + item.Qty_Ordered)
                    </td>
                </tr>
            }
        }
        else
        {
            <tr>
                <td colspan="6">No records found.</td>
            </tr>
        }
    </table>

    <div class="tbl-footer">
        <input type="submit" class="button" value="Process Returns" />
    </div>
}

2. 控制器层核心问题修复

  • 修改参数接收方式:接收int[] selectedOrderIds获取所有选中的订单ID
  • 修正更新逻辑:从数据库重新获取实体,避免直接使用传入的对象导致的错误,同时修正库存计算逻辑
  • 返回视图时传递Model:处理完成后重新获取数据并传递给视图,避免空引用

修改后的控制器代码:

//GET: ProductOrders/ReturnOrder
public ActionResult ReturnOrder(string orderNum)
{
    // 移除不必要的ProductOrder参数
    IEnumerable<ProductOrder> orders;
    if (!String.IsNullOrEmpty(orderNum))
    {
        // 处理OrderID可能不是字符串的情况,建议用int.TryParse
        if (int.TryParse(orderNum, out int orderId))
        {
            orders = db.ProductOrders.Where(x => x.OrderID == orderId).ToList();
        }
        else
        {
            orders = new List<ProductOrder>();
        }
    }
    else
    {
        orders = db.ProductOrders.OrderBy(x => x.OrderID).Where(x => x.Returned == null).ToList();
    }
    return View(orders);
}

//POST: ProductOrders/ReturnedOrder/
[HttpPost]
public ActionResult ReturnedOrder(int[] selectedOrderIds)
{
    if (selectedOrderIds != null && selectedOrderIds.Any())
    {
        foreach (int orderId in selectedOrderIds)
        {
            // 从数据库获取要更新的订单实体
            var productOrder = db.ProductOrders.FirstOrDefault(x => x.ProductOrderID == orderId);
            if (productOrder != null)
            {
                // 更新订单字段
                productOrder.Returned = true; // 标记为已退货
                productOrder.Qty_Returned = productOrder.Qty_Ordered; // 退货数量等于订购数量
                productOrder.Qty_Available += productOrder.Qty_Ordered; // 可用库存增加
                productOrder.Qty_On_Hand -= productOrder.Qty_Ordered; // 在手库存减少

                db.Entry(productOrder).State = EntityState.Modified;

                // 更新关联的Products表库存
                var product = db.Products.FirstOrDefault(x => x.ProductID == productOrder.ProductID);
                if (product != null)
                {
                    product.Qty_Available += productOrder.Qty_Ordered;
                    db.Entry(product).State = EntityState.Modified;
                }
            }
        }
        db.SaveChanges(); // 批量保存,提升性能
    }

    // 处理完成后重新获取数据,返回视图
    return RedirectToAction("ReturnOrder");
}

额外说明

  • 建议在数据库操作中使用事务,确保订单和库存更新的原子性,避免部分更新失败的情况
  • 可以添加错误处理逻辑,捕获数据库操作异常并返回友好提示
  • 原代码中OrderID.ToString() == orderNum存在类型转换隐患,改用int.TryParse更安全

内容的提问来源于stack exchange,提问作者Kip M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 06:06:28