ASP.Net Core 3.1:如何将下拉列表选中名称插入数据库表
技术问题:下拉列表选中项名称无法插入Stafftbl表,仅保存ID
使用ASP.Net Core搭配Entity Framework Core开发,尝试将下拉列表选中的CountryName、StateName和CityName插入Stafftbl表,但数据仅保存了ID,名称字段为空。
数据库表结构
Country表
| CountryId | CountryName |
|---|---|
| 1 | America |
| 2 | India |
State表
| StateId | StateName | CountryId |
|---|---|---|
| 1 | California | 1 |
City表
| CityId | CityName | StateId |
|---|---|---|
| 1 | Alameda | 1 |
期望的Stafftbl表结构
| StaffId | StaffName | Phone | CountryName | StateName | CityName | |
|---|---|---|---|---|---|---|
| 1 | Dauda Muhd | +12309 | em@gmail.com | America | California | Alameda |
现有代码
模型:CascadingModel
public class CascadingModel { public CascadingModel() { this.Countries = new List<SelectListItem>(); this.States = new List<SelectListItem>(); this.Cities = new List<SelectListItem>(); } public List<SelectListItem> Countries { get; set; } public List<SelectListItem> States { get; set; } public List<SelectListItem> Cities { get; set; } public int CountryId { get; set; } public int StateId { get; set; } public int CityId { get; set; } public int StaffId { get; set; } public string StaffName { get; set; } public string Phone { get; set; } public string Email { get; set; } public string CountryName { get; set; } public string StateName { get; set; } public string CityName { get; set; } }
控制器:DropdownController
public IActionResult Index() { CascadingModel model = new CascadingModel(); model.Countries = (from c in this.Context.Countries select new SelectListItem { Value = c.CountryId.ToString(), Text = c.CountryName }).ToList(); return View(model); } [HttpPost] public JsonResult AjaxMethod(string type, int value) { CascadingModel model = new CascadingModel(); switch (type) { case "ddlCountries": model.States = (from customer in _context.States where customer.CountryId == value select new SelectListItem { Value = customer.StateId.ToString(), Text = customer.StateName }).ToList(); break; case "ddlStates": model.Cities = (from customer in _context.Cities where customer.StateId == value select new SelectListItem { Value = customer.CityId.ToString(), Text = customer.CityName }).ToList(); break; } return Json(model); } [HttpPost] [ActionName("Index")] [ValidateAntiForgeryToken] public async Task<IActionResult> Index(CascadingModel cascadingModel) { var model = new StaffDetailVM() { StaffId = cascadingModel.StaffId, StaffName = cascadingModel.StaffName, PhoneNumber = cascadingModel.PhoneNumber, Email = cascadingModel.Email, CountryName = cascadingModel.CountryName, StateName = cascadingModel.StateName, CityName = cascadingModel.CityName, }; if (model != null) { await _context.Stafftbl.AddAsync(model); await _context.SaveChangesAsync(); } return View(cascadingModel); }
视图:Index.cshtml
<form method="post" asp-controller="Dropdown" asp-action="Index" > <div class="row"> <div class="col-md-4"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="StaffId" class="control-label"></label> <input asp-for="StaffId" class="form-control" /> <span asp-validation-for="StaffId" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="StaffName" class="control-label"></label> <input asp-for="StaffName" class="form-control" /> <span asp-validation-for="StaffName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="PhoneNumber" class="control-label"></label> <input asp-for="PhoneNumber" class="form-control" /> <span asp-validation-for="PhoneNumber" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Email" class="control-label"></label> <input asp-for="Email" class="form-control" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="CountryId" class="control-label"></label> <select id="ddlCountries" name="CountryName" asp-for="CountryId" asp-items="Model.Countries" class="form-control"> <option value="">--Please select--</option> </select> <span asp-validation-for="CountryId" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="StateId" class="control-label"></label> <select id="ddlStates" name="StateName" asp-for="StateId" asp-items="Model.States" class="form-control"> <option value="">--Please select--</option> </select> <span asp-validation-for="StateId" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="CityId" class="control-label"></label> <select id="ddlCities" name="CityName" asp-for="CityId" asp-items="Model.Cities" class="form-control"> <option value="">--Please select--</option> </select> <span asp-validation-for="CityId" class="text-danger"></span> </div> <div class="form-group"> <button type="submit" asp-action="SaveStaff" formnovalidate class="btn btn-primary">Create</button> </div> <div class="form-group"> <button type="submit" asp-action="SaveUpdate" formnovalidate class="btn btn-primary">Update</button> </div> <div class="form-group"> <input type="submit" value="Insert" class="btn btn-primary" /> </div> </div> </div> </form>
问题原因
- 视图中下拉列表手动设置了
name属性(如name="CountryName"),但asp-for绑定的是CountryId,导致表单提交时仅ID字段能获取值,名称字段为空。 - 控制器直接使用模型中空的名称字段赋值给
StaffDetailVM,最终数据库保存的就是空值。
解决方案
方案一:通过ID查询名称(推荐,安全可靠)
修改控制器的POST方法,利用接收的ID从数据库查询对应名称,再赋值保存:
[HttpPost] [ActionName("Index")] [ValidateAntiForgeryToken] public async Task<IActionResult> Index(CascadingModel cascadingModel) { // 查询国家名称 var country = await _context.Countries.FirstOrDefaultAsync(c => c.CountryId == cascadingModel.CountryId); // 查询州名称 var state = await _context.States.FirstOrDefaultAsync(s => s.StateId == cascadingModel.StateId); // 查询城市名称 var city = await _context.Cities.FirstOrDefaultAsync(ci => ci.CityId == cascadingModel.CityId); var model = new StaffDetailVM() { StaffId = cascadingModel.StaffId, StaffName = cascadingModel.StaffName, PhoneNumber = cascadingModel.Phone, // 注意:CascadingModel中是Phone,需与StaffDetailVM的PhoneNumber对应 Email = cascadingModel.Email, CountryName = country?.CountryName, StateName = state?.StateName, CityName = city?.CityName, }; if (model != null) { await _context.Stafftbl.AddAsync(model); await _context.SaveChangesAsync(); } return View(cascadingModel); }
同时修正视图中的下拉列表,移除手动设置的name属性,避免冲突:
<!-- 国家下拉列表 --> <select id="ddlCountries" asp-for="CountryId" asp-items="Model.Countries" class="form-control"> <option value="">--Please select--</option> </select> <!-- 州下拉列表 --> <select id="ddlStates" asp-for="StateId" asp-items="Model.States" class="form-control"> <option value="">--Please select--</option> </select> <!-- 城市下拉列表 --> <select id="ddlCities" asp-for="CityId" asp-items="Model.Cities" class="form-control"> <option value="">--Please select--</option> </select>
方案二:前端传递名称(不推荐,易被篡改)
若需从前端传递名称,可添加隐藏字段并通过JavaScript赋值:
在视图中添加隐藏字段:
<input type="hidden" asp-for="CountryName" id="hdnCountryName" /> <input type="hidden" asp-for="StateName" id="hdnStateName" /> <input type="hidden" asp-for="CityName" id="hdnCityName" />
添加JavaScript代码:
// 国家选择事件 document.getElementById('ddlCountries').addEventListener('change', function() { var selectedText = this.options[this.selectedIndex].text; document.getElementById('hdnCountryName').value = selectedText; }); // 州选择事件 document.getElementById('ddlStates').addEventListener('change', function() { var selectedText = this.options[this.selectedIndex].text; document.getElementById('hdnStateName').value = selectedText; }); // 城市选择事件 document.getElementById('ddlCities').addEventListener('change', function() { var selectedText = this.options[this.selectedIndex].text; document.getElementById('hdnCityName').value = selectedText; });
同样需要移除下拉列表中的name属性,确保ID字段正常绑定。
内容的提问来源于stack exchange,提问作者dausa
相关产品推荐
相关产品推荐

