ASP.NET MVC使用ViewModel保存下拉列表选中项到数据库问题求助
问题1:GET Create方法是否合理
你的原有GET方法不符合需求,核心问题是生成下拉列表时没有绑定ClientId作为提交值:
你只查询了Client的Name字段生成SelectList,未指定DataValueField(提交值对应字段)和DataTextField(展示值对应字段),导致下拉列表的提交值是客户名称而非ClientId,后端无法拿到正确的外键值。
修正后的GET方法代码:
public IActionResult Create() { // 同时查询ClientId和Name字段 var clients = _context.Client.Select(r => new { r.ClientId, r.Name }).ToList(); var viewmodel = new CreateProjectViewModel { // 指定SelectList的value对应ClientId,text对应Name Clients = new SelectList(clients, "ClientId", "Name") }; return View(viewmodel); }
问题2:@Html.DropDownListFor的参数配置
你原有代码中@Html.DropDownListFor(model => model.ClientId, Model.Clients, "---Select Client---", new { @class = "form-control" })的参数配置是正确的,不需要修改。
你遇到的空引用报错和该配置无关,报错根源是POST逻辑返回视图时未重新填充下拉列表数据源。如果要优化语义,可以把上方的Label绑定改为@Html.LabelFor(model => model.ClientId, "客户名称", htmlAttributes: new { @class = "control label col-md-2" })。
问题3:POST Create方法修正
原有POST方法的核心问题是验证失败返回视图时未重新填充Clients集合:当ModelState.IsValid为false时,你直接返回空视图,视图渲染下拉列表时读取不到Model.Clients就会触发空引用报错。
修正后的POST方法代码:
[ValidateAntiForgeryToken] public async Task<ActionResult> Create(CreateProjectViewModel model) { if (ModelState.IsValid) { var project = new Project() { Name = model.Name, ClientId = model.ClientId, Budget = model.Budget, BusinessCase = model.BusinessCase, StartDate = model.StartDate, FinishDate = model.FinishDate }; _context.Add(project); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } // 验证失败时重新填充下拉列表数据源,再返回视图 var clients = _context.Client.Select(r => new { r.ClientId, r.Name }).ToList(); model.Clients = new SelectList(clients, "ClientId", "Name"); return View(model); }
额外优化建议
你的CreateProjectViewModel中不需要保留Client、ProjectMembers、ProjectId这些未在表单中用到的属性,删除多余属性可以避免不必要的模型绑定开销。
内容的提问来源于stack exchange,提问作者Matt

