如何将问题字符串及对应选项列表同步添加至数据库?
解决方法:将问题与选项一同存入数据库
看起来你已经搞定了问题的存储,但卡在了关联选项这块。别担心,咱们一步步来解决这个问题,核心是利用EF Core的一对多关系和模型绑定来实现问题与选项的批量保存。
1. 先确认模型的关联关系
首先确保你的Question和Option模型已经正确配置了一对多关联,这是EF Core自动级联保存的基础:
Question.cs
public class Question { public int Id { get; set; } [Required] public string Text { get; set; } // 其他问题相关属性(比如分类、难度等) // 导航属性:一个问题对应多个选项 public ICollection<Option> Options { get; set; } = new List<Option>(); }
Option.cs
public class Option { public int Id { get; set; } [Required] public string Text { get; set; } // 可选:标记是否为正确答案 public bool IsCorrect { get; set; } // 外键:关联所属的问题 public int QuestionId { get; set; } // 导航属性:选项属于一个问题 public Question Question { get; set; } }
别忘了在ApplicationDbContext中注册这两个实体:
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Question> Questions { get; set; } public DbSet<Option> Options { get; set; } }
2. 调整QuestionController的提交方法
你不需要单独保存选项,EF Core会自动级联保存关联的Options集合,只要你在保存Question时,它的Options已经被正确填充。修改你的AddQuestion POST方法:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> AddQuestion(Question question) { if (ModelState.IsValid) { // 只需要添加Question,EF Core会自动添加关联的Options _context.Questions.Add(question); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); // 跳转到问题列表页 } // 验证失败返回视图,保留用户输入 return View(question); }
3. 修改AddQuestion视图,实现选项的绑定
关键是让视图的输入框符合ASP.NET Core模型绑定的规则——集合类型的输入框name属性需要写成Options[N].PropertyName(N是索引,从0开始),这样模型绑定器才能把输入的选项填充到Question.Options集合中。
静态选项示例(固定数量)
如果你的问题选项数量固定(比如4个),可以直接用循环生成输入框:
@model Question <h1>Add New Question</h1> <form asp-action="AddQuestion"> <!-- 问题文本输入 --> <div class="form-group mb-3"> <label asp-for="Text" class="form-label">Question Text</label> <input asp-for="Text" class="form-control" /> <span asp-validation-for="Text" class="text-danger"></span> </div> <!-- 选项区域 --> <h3 class="mb-2">Answer Options</h3> @for (int i = 0; i < 4; i++) { <div class="border p-3 mb-2"> <div class="form-group"> <label>Option @(i+1) Text</label> <input type="text" asp-for="Options[i].Text" class="form-control" /> <span asp-validation-for="Options[i].Text" class="text-danger"></span> </div> <div class="form-check mt-2"> <input class="form-check-input" asp-for="Options[i].IsCorrect" /> <label class="form-check-label" asp-for="Options[i].IsCorrect"> Mark as correct answer </label> </div> </div> } <button type="submit" class="btn btn-primary">Save Question & Options</button> </form>
动态添加选项(可选)
如果需要支持用户动态添加任意数量的选项,可以用JavaScript实现:
在视图底部添加这段JS:
<script> let currentOptionIndex = 4; // 初始有4个选项,从第5个开始计数 // 添加按钮点击事件 document.getElementById("add-option-btn").addEventListener("click", function() { // 克隆现有选项模板 const optionTemplate = document.querySelector(".option-template").cloneNode(true); optionTemplate.classList.remove("d-none"); // 移除隐藏类 // 更新输入框的name和id属性,符合模型绑定规则 const textInput = optionTemplate.querySelector("[name^='Options']"); textInput.name = `Options[${currentOptionIndex}].Text`; textInput.id = `Options_${currentOptionIndex}__Text`; const correctCheckbox = optionTemplate.querySelector("[type='checkbox']"); correctCheckbox.name = `Options[${currentOptionIndex}].IsCorrect`; correctCheckbox.id = `Options_${currentOptionIndex}__IsCorrect`; // 清空输入值和复选框状态 textInput.value = ""; correctCheckbox.checked = false; // 添加到选项容器中 document.getElementById("options-container").appendChild(optionTemplate); currentOptionIndex++; }); </script>
然后修改视图的选项区域:
<!-- 选项容器 --> <div id="options-container"> <!-- 初始4个选项 --> @for (int i = 0; i < 4; i++) { <div class="border p-3 mb-2"> <div class="form-group"> <label>Option @(i+1) Text</label> <input type="text" asp-for="Options[i].Text" class="form-control" /> <span asp-validation-for="Options[i].Text" class="text-danger"></span> </div> <div class="form-check mt-2"> <input class="form-check-input" asp-for="Options[i].IsCorrect" /> <label class="form-check-label" asp-for="Options[i].IsCorrect"> Mark as correct answer </label> </div> </div> } <!-- 隐藏的选项模板,用于克隆 --> <div class="option-template border p-3 mb-2 d-none"> <div class="form-group"> <label>Option Text</label> <input type="text" name="Options[0].Text" class="form-control" /> </div> <div class="form-check mt-2"> <input class="form-check-input" type="checkbox" name="Options[0].IsCorrect" /> <label class="form-check-label"> Mark as correct answer </label> </div> </div> </div> <!-- 添加选项按钮 --> <button type="button" id="add-option-btn" class="btn btn-secondary mb-3">Add Another Option</button>
4. 验证与测试
- 确保
Option的Text属性添加了[Required]特性,这样用户必须填写每个选项的内容。 - 测试提交:填写问题和选项,点击提交后,查看数据库的
Questions和Options表,确认问题和对应的选项都被正确保存,且Options表的QuestionId字段正确关联到问题的Id。
这样就能实现问题和选项的一键保存啦!
内容的提问来源于stack exchange,提问作者Guga Todua
相关产品推荐
相关产品推荐

