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

解决联动DropdownList值存入数据库时的InvalidOperationException错误

问题:动态加载DropdownList选中值无法保存到数据库,且视图报错

错误信息

InvalidOperationException: 不存在键为'StockItems[0].StockId'的'IEnumerable'类型ViewData项

现有代码

Controller代码

public IActionResult Create()
{
    List<Category> categories = _dbcontext.Category.ToList();
    ViewBag.ListCategories = new SelectList(categories, "CategoryId", "CategoryName");            
    Invoice invoice= new Invoice();
    invoice.StockItems.Add(new StockItems() { StockItemsId = 1});
    return View(decharge); // 此处存在笔误,应为return View(invoice);
}
[HttpPost]
public IActionResult Create(Invoice invoice)
{
   if (invoice!= null)
   {
        _dbcontext.Invoice.Add(invoice);
        _dbcontext.SaveChanges();
        return RedirectToAction("Index");
    }
    return View();
}

[HttpPost]
public IActionResult GetStockByCat(int CatId)
{
    List<Stock> stocks = new List<Stock>();
    stocks = _dbcontext.Stock.Where(s => s.CategoryId == CatId).ToList();
    SelectList stocksList = new SelectList(stocks, "StockId", "Name");
    return Json(stocksList);
}

Create视图代码

<table class="table table-bordered table-hover">
    <thead>
        <tr>
            ....
        </tr>
    </thead>
    <tbody>
    @for (int i = 0; i < Model.StockItems.Count; i++)
    {
        <tr>
            <td>@Html.DropDownList("Category", ViewBag.ListCategories, null, new { @class = "form-control", @onchange = "GetStocks(this)" })</td>
            <td>@Html.DropDownListFor(x => x.StockItems[i].StockId,null, "--Select --",  new { htmlAttributes = new { @class = "form-control",@id= "stocks", @name = "stocks"} })</td>

        </tr>
     }
    </tbody>
</table>

<script language="javascript" type="text/javascript">
function GetStocks(dropdown1) {
    var procemessage = "<option value='0'> Please wait...</option>";
    var dropdown2 = $(dropdown1).closest('tr').find('#stocks');
    dropdown2.html(procemessage).show();
    var url = '@Url.Action("GetStockByCat", "Stock")';

    $.ajax({
        url: url,
        data: { CatId: dropdown1.value},
        cache: false,
        type: "POST",
        success: function (data) {
            var markup = "<option value='0'>---------</option>";
            for (var x = 0; x < data.length; x++) {
                markup += '<option value="' + data[x].value + '">' + data[x].text + '</option>';
            }
            dropdown2.html(markup).show();
            
        },
        error: function (reponse) {
            alert("error : " + reponse);
        }
    });        
}
</script>

解决方案

1. 修复视图加载报错

DropDownListFor的第二个参数不能传null,否则会自动去ViewData中查找对应键的选项集合。由于我们是动态加载选项,直接传入空的SelectList即可避免报错,同时修正重复ID和属性嵌套问题:

修改视图中第二个DropdownList代码:

<td>@Html.DropDownListFor(x => x.StockItems[i].StockId, new SelectList(Enumerable.Empty<SelectListItem>()), "--Select --", new { @class = "form-control stocks-dropdown" })</td>
  • 用stocks-dropdown类代替重复的id="stocks",保证HTML元素ID唯一性
  • 移除错误的htmlAttributes嵌套,直接设置class属性
  • 传入空SelectList,跳过ViewData查找逻辑

2. 修正JS元素查找逻辑

因为现在用类选择器,修改JS中的dropdown2查找代码:

var dropdown2 = $(dropdown1).closest('tr').find('.stocks-dropdown');

3. 修复Controller笔误

把Create方法中的return View(decharge);改为return View(invoice);,否则视图接收的Model为空,循环逻辑会直接报错。

4. 完善表单提交回退逻辑

当表单提交失败时,需要重新填充分类列表,避免视图再次报错:

[HttpPost]
public IActionResult Create(Invoice invoice)
{
   if (ModelState.IsValid) // 用ModelState判断更严谨
   {
        _dbcontext.Invoice.Add(invoice);
        _dbcontext.SaveChanges();
        return RedirectToAction("Index");
    }
    // 提交失败时重新填充分类列表
    ViewBag.ListCategories = new SelectList(_dbcontext.Category.ToList(), "CategoryId", "CategoryName");
    return View(invoice); // 返回原Model保留用户已输入内容
}

5. 优化AJAX请求(可选)

将GetStockByCat改为HttpGet请求,符合REST数据获取的规范:

[HttpGet]
public IActionResult GetStockByCat(int CatId)
{
    var stocks = _dbcontext.Stock.Where(s => s.CategoryId == CatId)
                                .Select(s => new SelectListItem { Value = s.StockId.ToString(), Text = s.Name })
                                .ToList();
    return Json(stocks);
}

同时修改JS中的请求类型:type: "GET"。

最终效果

  • 视图加载不再报错
  • 选择分类后可动态加载对应库存选项
  • 提交表单时StockItems[i].StockId能正确绑定到Invoice对象并保存到数据库

内容的提问来源于stack exchange,提问作者user3309231

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:45:41