ASP.NET Core中获取Category Id并关联插入另一表的问题
问题背景
我需要在ASP.NET Core中将食品及其分类数据插入两个关联表。现有创建食品的方法可添加名称、图片等信息,但最初无法从分类列表获取Category Id;后续解决ID获取问题后,插入FoodSelectedCategory表时出现外键冲突错误。
初始问题:无法获取Category Id
相关代码如下:
控制器创建方法
public async Task<IActionResult> CreateFoodByAdmin(CreateFoodViewModel createFoodViewModel) { if (ModelState.IsValid) { var result = await _foodService.CreateFoodByAdmin(createFoodViewModel); switch (result) { case CreateFoodResult.FoodIsExist: await GetFoodCategory(); ModelState.AddModelError("FoodTitle", "Food Title exists"); return View(createFoodViewModel); case CreateFoodResult.NotFound: return RedirectToAction("NotFound"); case CreateFoodResult.Success: return RedirectToAction("FoodList"); } } await GetFoodCategory(); return View(createFoodViewModel); }
视图渲染分类复选框
<label >Food Category List</label> <ul> <span asp-validation-for="FoodCategoryId"></span> @foreach (var foodCat in foodCategory) { <li> <input class="form-check-input" name="FoodSelectedCategories" type="checkbox" value="@foodCat.FoodCategoryId" id="categoryCheckbox"> @foodCat.FoodCategoryTitle </li> } </ul>
ViewData传递分类列表
List<FoodCategoryViewModel> foodCategory = ViewData["FoodCategory"] as List<FoodCategoryViewModel>;
调试时发现除FoodCategoryId外,其他数据均可正常接收。
第一次更新:解决ID获取问题
我在CreateFoodViewModel中添加属性:
public List<int> FoodCategoryId { get; set; }
同时有获取分类列表的方法:
public async Task GetFoodCategory() { var foodCategory = await _foodService.GetAllFoodCategory(); ViewData["FoodCategory"] = foodCategory; }
现在可成功获取选中的分类ID,但插入关联表时出现新问题。
最新问题:外键冲突错误
插入FoodSelectedCategory表时抛出异常:
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_FoodSelectedCategories_FoodCategories_FoodCategoryId". The conflict occurred in database "EvSef_db", table "dbo.FoodCategories", column 'FoodCategoryId'.
关联的插入方法代码:
public async Task AddFoodCategoryToFoodList(int foodId, List<int> foodCategoryId) { if (!foodCategoryId.Any()) return; foreach (var foodCat in foodCategoryId) { FoodSelectedCategory x = new FoodSelectedCategory() { FoodId = foodId, FoodCategoryId = foodCat, RegisterDate = DateTime.Now, }; await _foodRepository.AddFoodCategoryToFood(x); await _foodRepository.SaveChanges(); } }
解决外键冲突的步骤
1. 检查传入的分类ID有效性
外键冲突的核心原因是尝试插入的FoodCategoryId在FoodCategories表中不存在:
- 调试
AddFoodCategoryToFoodList方法,查看foodCategoryId列表中的值,对比数据库FoodCategories表的FoodCategoryId,确认是否存在无效ID。 - 检查视图中复选框的
value是否正确绑定了foodCat.FoodCategoryId(比如字符串转数字时出错、ViewModel传递时类型不匹配)。
2. 修正视图参数名称匹配
视图中复选框的name是FoodSelectedCategories,但ViewModel中的属性是FoodCategoryId,名称不匹配会导致模型绑定错误,可能传入错误ID(如空值或默认值)。修改视图中复选框的name:
<input class="form-check-input" name="FoodCategoryId" type="checkbox" value="@foodCat.FoodCategoryId" id="categoryCheckbox">
3. 添加插入前的验证逻辑
在插入前验证每个分类ID是否存在于数据库中,避免无效插入:
public async Task AddFoodCategoryToFoodList(int foodId, List<int> foodCategoryId) { if (!foodCategoryId.Any()) return; // 获取所有有效的分类ID var validCategoryIds = await _foodRepository.GetAllFoodCategoryIds(); foreach (var foodCat in foodCategoryId) { if (!validCategoryIds.Contains(foodCat)) { // 跳过无效ID或抛出明确错误 continue; } FoodSelectedCategory x = new FoodSelectedCategory() { FoodId = foodId, FoodCategoryId = foodCat, RegisterDate = DateTime.Now, }; await _foodRepository.AddFoodCategoryToFood(x); } // 统一保存更改,避免多次调用SaveChanges影响性能 await _foodRepository.SaveChanges(); }
同时在仓储层添加获取所有分类ID的方法:
public async Task<List<int>> GetAllFoodCategoryIds() { return await _context.FoodCategories.Select(c => c.FoodCategoryId).ToListAsync(); }
4. 额外验证食品ID有效性
虽然错误提示指向分类表外键,但也可确认foodId是否已成功插入食品表,避免因食品ID无效引发连锁问题。
内容的提问来源于stack exchange,提问作者Maryam12 forex

