EF Core批量更新任务数据:模型绑定IList为空的问题与解决
EF Core任务复选框变更绑定与保存问题
问题描述
我开发了一个EF Core应用,用于创建新员工并为其分配多项任务。员工完成任务后,需打开列有所有任务的表单,勾选对应任务的复选框后提交表单。
我了解如何跟踪单个实体的变更,但将任务加载到IList<TaskAssignment>后,始终无法通过模型绑定跟踪变更——Post方法中的IList始终为空,也找不到可行的方法将变更保存到数据库表中。尝试了网上多种方法,导致代码变得混乱。
原模型代码
public class TasksOutstandingModel : DI_BasePageModel { [BindProperty] public IList<TaskAssignment>? Tasks { get; set; } public async Task<IActionResult> OnGetAsync(int? id) { var tasks = _tasksContext.TaskAssignment.Where(t => t.EmpReferenceID == id); Tasks = await tasks.ToListAsync(); if (tasks == null) { return NotFound(id); } return Page(); } public async Task<IActionResult> OnPostAsync(uint? id, IList<TaskAssignment> tasksList) { if (!ModelState.IsValid) { return Page(); } var originalEntity = await _tasksContext.TaskAssignment.AsNoTracking().FirstOrDefaultAsync(me => me.EmpReferenceID == id && me.HRID == 1); var changed = Request.Form["hr+1"]; bool changedContrSent = originalEntity.Done != Convert.ToBoolean(changed); if (changedContrSent) { //do stuff } foreach (var task in tasksList) { TaskAssignment taskAssignment = _tasksContext.TaskAssignment.Find(task.TaskAssignmentID); taskAssignment.Done = task.Done; _tasksContext.Entry(taskAssignment).State = EntityState.Modified; Console.WriteLine(taskAssignment.TaskAssignmentID); } try { await _tasksContext.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TasksExits((int)Tasks.FirstOrDefault().EmpReferenceID)) { return NotFound(); } else { throw; } } return RedirectToPage("./TasksOutstanding", Tasks.FirstOrDefault().EmpReferenceID); } }
原视图代码(部分)
<form method="post"> @for (int i = 0; i < Model.Tasks.Count(); i++) { <input type="hidden" asp-for="Tasks[i].TaskAssignmentID"/> <input type="hidden" asp-for="Tasks[i].EmpReferenceID"/> <input type="hidden" asp-for="Tasks[i].AssistantID"/> <input type="hidden" asp-for="Tasks[i].EduID"/> <input type="hidden" asp-for="Tasks[i].FKID"/> <input type="hidden" asp-for="Tasks[i].HRID"/> <input type="hidden" asp-for="Tasks[i].PayrollID"/> <input type="hidden" asp-for="Tasks[i].DueDateInD"/> <input type="hidden" asp-for="Tasks[i].Dependency"/> <input type="hidden" asp-for="Tasks[i].Done"/> <input type="hidden" asp-for="Tasks[i].ITId"/> } <div class="correctWidth"> <button type="button" class="collapsibleHeading">Aufgaben für Bildungsmanagement</button> <div class="collapsing-content"> @{ var allEdu = Model.Tasks.Where(t => t.EduID != null); foreach (var item in allEdu) { <div class="form-group form-check"> @* if the item is already marked as done then we disable the checkbox so it can't be unchecked *@ @if (item.Done || disable) { <input class="form-check-input" asp-for="@item.Done" name="edu+@item.EduID" disabled/> disable = false; } else { <input class="form-check-input" asp-for="@item.Done" name="edu+@item.EduID" /> } @if (shortdesc != "") { <button type="button" class="collapsible"> <div class="summaryText">@summary</div> @if (!duedate.Equals(01 / 01 / 0001)) { <div class="dueDateDiv">@duedate</div> } else { <div class="dueDateDiv"></div> } <div class="SymbolDiv"></div> </button> <div class="collapsing-content"> @Html.Raw(shortdesc) </div> } else { <div class="notCollapsible"> <div class="summaryText">@summary</div> </div> } </div> } } </div> </div> <div class="form-group"> <input type="hidden" asp-for="Tasks.First().EmpReferenceID"/> <input type="submit" value="Speichern" class="btn btn-primary"/> </div> </form>
解决方法
编辑:
感谢Jason Pan的建议,代码现已正常运行。在视图中移除了不必要的for循环;在控制器中添加了UpdateTasks()方法,通过处理Request.Form获取复选框的变更值,更新对应实体并标记为修改状态,最后在OnPostAsync中调用该方法并保存变更到数据库:
UpdateTasks方法代码
private void UpdateTasks(uint? ident) { string ss = ""; byte key = 0; bool donezoes = false; var tasks = _tasksContext.TaskAssignment.Where(t => t.EmpReferenceID == ident); Tasks = tasks.ToList(); var dict = Request.Form.ToDictionary(d => d.Key, d => d.Value); foreach (var item in dict) { //获取所有变更的变量 //Key是HTML元素的名称 //Value是复选框的值,即true或false if (item.Key.Contains("EmpReferenceID")) break; if (item.Key.Contains("edu")) { //复选框命名为"edu+x",x是需要从数据库中获取的对象ID ss = item.Key.Substring(4); key = Convert.ToByte(ss); //将值转换为布尔类型 donezoes = Convert.ToBoolean(item.Value); TaskAssignment ta = Tasks.FirstOrDefault(x => x.EduID == key); //更新数据库实体的Done状态 ta.Done = donezoes; //标记实体为已修改 _tasksContext.Entry(ta).State = EntityState.Modified; } //其他类型任务的处理逻辑类似 } }
修改后的OnPostAsync方法
public async Task<IActionResult> OnPostAsync(uint? id) { if (!ModelState.IsValid) { return Page(); } UpdateTasks(id); ... try { await _tasksContext.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TasksExits((int)Tasks.FirstOrDefault().EmpReferenceID)) { return NotFound(); } else { throw; } } return RedirectToPage("./TasksOutstanding", Tasks.FirstOrDefault().EmpReferenceID); }
内容的提问来源于stack exchange,提问作者Jat
相关产品推荐
相关产品推荐

