如何在Equipment创建视图中同步处理关联Location表的字段录入
问题背景
我的数据库架构中,Location表关联了Floor、Room、Rack三个表,Equipment表关联Location和EquipmentStatus表。
对应的实体类代码如下:
Equipment.cs
public class Equipment { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] [DisplayName("Serial Number")] public string Id { get; set; } [Required] public string Name { get; set; } [Required] public int Amount { get; set; } public int EquipmentStatusId { get; set; } [ValidateNever] public EquipmentStatus? EquipmentStatus { get; set; } public int LocationId { get; set; } [ValidateNever] public Location? Location { get; set; } [Required] [DisplayName("Internal or Consigned")] public string InternalOrConsigned { get; set; } [DisplayName("EOL Date")] public DateTime? EOLDate { get; set; } public string? EOLDescription { get; set; } [ValidateNever] [DisplayName("Image")] public string? ImageUrl { get; set; } }
Location.cs
public class Location { [Key] public int Id { get; set; } public int FloorId { get; set; } [ValidateNever] public Floor? Floor { get; set; } public int RoomId { get; set; } [ValidateNever] public Room? Room { get; set; } public int RackId { get; set; } [ValidateNever] public Rack? Rack { get; set; } [Required] public string Row { get; set; } }
我希望在Equipment的Create.cshtml视图中完成所有属性的录入,已经掌握用SelectListItem处理EquipmentStatusId的下拉选择,但Location关联多个表且包含多属性,不清楚如何处理LocationId的录入。
当前EquipmentsTestController.cs的Create方法代码:
// GET: User/EquipmentsTest/Create public IActionResult Create() { ViewData["EquipmentStatusId"] = new SelectList(_context.EquipmentStatuses, "Id", "Name"); ViewData["LocationId"] = new SelectList(_context.Locations, "Id", "Row"); return View(); } // POST: User/EquipmentsTest/Create [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create(Equipment equipment) { if (ModelState.IsValid) { _context.Add(equipment); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } ViewData["EquipmentStatusId"] = new SelectList(_context.EquipmentStatuses, "Id", "Name", equipment.EquipmentStatusId); ViewData["LocationId"] = new SelectList(_context.Locations, "Id", "Row", equipment.LocationId); return View(equipment); }
当前Create.cshtml代码:
<form asp-action="Create"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="Id" class="control-label"></label> <input asp-for="Id" class="form-control" /> <span asp-validation-for="Id" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input asp-for="Name" class="form-control" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Amount" class="control-label"></label> <input asp-for="Amount" class="form-control" /> <span asp-validation-for="Amount" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EquipmentStatusId" class="control-label"></label> <select asp-for="EquipmentStatusId" class ="form-control" asp-items="ViewBag.EquipmentStatusId"></select> </div> <div class="form-group"> <label asp-for="LocationId" class="control-label"></label> <select asp-for="LocationId" class ="form-control" asp-items="ViewBag.LocationId"></select> </div> <div class="form-group"> <label asp-for="InternalOrConsigned" class="control-label"></label> <input asp-for="InternalOrConsigned" class="form-control" /> <span asp-validation-for="InternalOrConsigned" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EOLDate" class="control-label"></label> <input asp-for="EOLDate" class="form-control" /> <span asp-validation-for="EOLDate" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EOLDescription" class="control-label"></label> <input asp-for="EOLDescription" class="form-control" /> <span asp-validation-for="EOLDescription" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="ImageUrl" class="control-label"></label> <input asp-for="ImageUrl" class="form-control" /> <span asp-validation-for="ImageUrl" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form>
解决方案
有两种常见处理方式,根据业务需求选择:
方案1:选择已存在的Location(优化下拉选项可读性)
当前代码中Location的下拉仅显示Row字段,用户无法明确该位置的完整信息。可以修改SelectList的显示文本,拼接关联的Floor、Room、Rack名称,让用户清晰选择。
修改Controller代码
在GET和POST方法中,更新ViewData["LocationId"]的赋值:
ViewData["LocationId"] = new SelectList( _context.Locations .Include(l => l.Floor) .Include(l => l.Room) .Include(l => l.Rack), "Id", l => $"{l.Floor.Name} - {l.Room.Name} - {l.Rack.Name} - 行:{l.Row}" );
注意:需确保
Floor、Room、Rack实体类包含Name属性,若属性名不同需对应修改。
View代码无需修改
保持原有的select控件即可,提交后LocationId会自动绑定到Equipment实体,直接保存即可。
方案2:创建Equipment时同时新建Location
如果业务需要在添加设备时直接录入新的位置信息,而非选择已有位置,需通过ViewModel实现:
步骤1:创建ViewModel
定义包含Equipment和Location所有字段的ViewModel:
public class EquipmentCreateViewModel { // Equipment属性 public string Id { get; set; } public string Name { get; set; } public int Amount { get; set; } public int EquipmentStatusId { get; set; } public string InternalOrConsigned { get; set; } public DateTime? EOLDate { get; set; } public string? EOLDescription { get; set; } public string? ImageUrl { get; set; } // Location属性 public int FloorId { get; set; } public int RoomId { get; set; } public int RackId { get; set; } public string Row { get; set; } }
步骤2:修改Controller代码
GET方法:传递关联表的下拉数据
public IActionResult Create() { ViewData["EquipmentStatusId"] = new SelectList(_context.EquipmentStatuses, "Id", "Name"); ViewData["FloorId"] = new SelectList(_context.Floors, "Id", "Name"); ViewData["RoomId"] = new SelectList(_context.Rooms, "Id", "Name"); ViewData["RackId"] = new SelectList(_context.Racks, "Id", "Name"); return View(); }
POST方法:先保存Location,再关联Equipment
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create(EquipmentCreateViewModel vm) { if (ModelState.IsValid) { // 创建并保存新Location var newLocation = new Location { FloorId = vm.FloorId, RoomId = vm.RoomId, RackId = vm.RackId, Row = vm.Row }; _context.Locations.Add(newLocation); await _context.SaveChangesAsync(); // 创建Equipment并关联新Location的Id var newEquipment = new Equipment { Id = vm.Id, Name = vm.Name, Amount = vm.Amount, EquipmentStatusId = vm.EquipmentStatusId, LocationId = newLocation.Id, InternalOrConsigned = vm.InternalOrConsigned, EOLDate = vm.EOLDate, EOLDescription = vm.EOLDescription, ImageUrl = vm.ImageUrl }; _context.Equipments.Add(newEquipment); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } // 验证失败时重新加载下拉数据 ViewData["EquipmentStatusId"] = new SelectList(_context.EquipmentStatuses, "Id", "Name", vm.EquipmentStatusId); ViewData["FloorId"] = new SelectList(_context.Floors, "Id", "Name", vm.FloorId); ViewData["RoomId"] = new SelectList(_context.Rooms, "Id", "Name", vm.RoomId); ViewData["RackId"] = new SelectList(_context.Racks, "Id", "Name", vm.RackId); return View(vm); }
步骤3:修改Create.cshtml视图
替换原有的LocationId下拉控件为Location的各个字段输入:
<form asp-action="Create"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <!-- Equipment原有字段保持不变 --> <div class="form-group"> <label asp-for="Id" class="control-label"></label> <input asp-for="Id" class="form-control" /> <span asp-validation-for="Id" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input asp-for="Name" class="form-control" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Amount" class="control-label"></label> <input asp-for="Amount" class="form-control" /> <span asp-validation-for="Amount" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EquipmentStatusId" class="control-label"></label> <select asp-for="EquipmentStatusId" class="form-control" asp-items="ViewBag.EquipmentStatusId"></select> </div> <div class="form-group"> <label asp-for="InternalOrConsigned" class="control-label"></label> <input asp-for="InternalOrConsigned" class="form-control" /> <span asp-validation-for="InternalOrConsigned" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EOLDate" class="control-label"></label> <input asp-for="EOLDate" class="form-control" /> <span asp-validation-for="EOLDate" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="EOLDescription" class="control-label"></label> <input asp-for="EOLDescription" class="form-control" /> <span asp-validation-for="EOLDescription" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="ImageUrl" class="control-label"></label> <input asp-for="ImageUrl" class="form-control" /> <span asp-validation-for="ImageUrl" class="text-danger"></span> </div> <!-- 新增Location字段输入 --> <div class="form-group"> <label asp-for="FloorId" class="control-label"></label> <select asp-for="FloorId" class="form-control" asp-items="ViewBag.FloorId"></select> </div> <div class="form-group"> <label asp-for="RoomId" class="control-label"></label> <select asp-for="RoomId" class="form-control" asp-items="ViewBag.RoomId"></select> </div> <div class="form-group"> <label asp-for="RackId" class="control-label"></label> <select asp-for="RackId" class="form-control" asp-items="ViewBag.RackId"></select> </div> <div class="form-group"> <label asp-for="Row" class="control-label"></label> <input asp-for="Row" class="form-control" /> <span asp-validation-for="Row" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form>
内容的提问来源于stack exchange,提问作者MarrionBerry
相关产品推荐
相关产品推荐

