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

如何向包含关联数据的MVC模型提交POST请求?

解决Products模型POST提交时Supplier/Category导致ModelState无效的问题

问题原因

在C# 8及以上的可为null引用类型模式下,你的Products模型中Supplier和Category导航属性属于未标记可空的引用类型,模型绑定器会默认将它们判定为必填项。但表单仅提交了SupplierID和CategoryID外键值,无法为这两个导航属性赋值,导致它们为null,触发验证错误,最终ModelState.IsValid返回false。

解决方案

方案1:修改模型,标记导航属性为可空

直接在模型中给导航属性添加?,明确其为可空引用类型:

public class Products
{
    [Key]
    public int ProductID { get; set; }
    [Required]
    public string ProductName { get; set; } = string.Empty;
    [ForeignKey("Supplier")]
    public int SupplierID { get; set; }
    // 标记为可空引用类型
    public Suppliers? Supplier { get; set; }
    [ForeignKey("Category")]
    public int CategoryID { get; set; }
    // 标记为可空引用类型
    public Categories? Category { get; set; }
    public string? QuantityPerUnit { get; set; }
    public decimal UnitPrice { get; set; }
    public int UnitsInStock { get; set; }
    public int UnitsOnOrder { get; set; }
    public int ReorderLevel { get; set; }
    public string? Discontinued { get; set; }
}

修改后,模型验证仅会校验SupplierID和CategoryID的有效性,不再强制要求导航属性有值,匹配表单提交逻辑。

方案2:在控制器中手动移除无效验证项

若暂时不想修改模型,可在POST方法中手动清除导航属性的验证错误:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued")] Products products)
{
    // 移除导航属性的验证错误
    ModelState.Remove(nameof(Products.Supplier));
    ModelState.Remove(nameof(Products.Category));

    if (id != products.ProductID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(products);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ProductsExists(products.ProductID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    // 重新填充下拉选单数据
    ViewData["CategoryID"] = new SelectList(_context.Categories, "CategoryID", "CategoryID", products.CategoryID);
    ViewData["SupplierID"] = new SelectList(_context.Suppliers, "SupplierID", "SupplierID", products.SupplierID);
    return View(products);
}

方案3:使用视图模型推荐

创建仅包含表单所需字段的视图模型,避免导航属性引发的验证问题:

public class ProductEditViewModel
{
    public int ProductID { get; set; }
    [Required]
    public string ProductName { get; set; } = string.Empty;
    public int SupplierID { get; set; }
    public int CategoryID { get; set; }
    public string? QuantityPerUnit { get; set; }
    public decimal UnitPrice { get; set; }
    public int UnitsInStock { get; set; }
    public int UnitsOnOrder { get; set; }
    public int ReorderLevel { get; set; }
    public string? Discontinued { get; set; }
}

在控制器GET方法中,将Products实体映射到视图模型传递给视图;POST方法中接收视图模型,再映射回Products实体完成数据库更新。这种方式更贴合MVC分层设计,也能避免过度暴露实体属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 19:51:09