.NET Core中点击按钮修改书籍Availability属性的实现异常问题
问题分析与解决
你的代码存在两个关键问题,直接导致了空引用异常和库存更新不生效:
- 未持久化数据库修改:修改书籍
Availability属性后,没有调用EF Core的保存方法,更新不会写入数据库。 - 视图无有效模型传入:直接返回
View("Index")但未传递书籍列表数据,Razor视图接收的Model为null,遍历触发NullReferenceException。
修复方案
1. 修正Loan方法,完成更新保存与模型传递
修改后的方法需同时实现库存修改、数据库保存、更新后数据查询三个核心动作:
public async Task<IActionResult> Loan(string id) { if (id == null || _context.Books == null) { return NotFound(); } var book = await _context.Books .FirstOrDefaultAsync(m => m.BookCode == id); if (book == null) { return NotFound(); } else if (book.Availability == 0) { return BadRequest(new { Message = "书籍已无库存,无法借出" }); } else { // 减少库存 book.Availability = (sbyte)(book.Availability - 1); // 将更新写入数据库 await _context.SaveChangesAsync(); // 查询更新后的完整书籍列表 var updatedBooks = await _context.Books.ToListAsync(); // 传递模型到Index视图 return View("Index", updatedBooks); } }
2. 实现归还功能(复用借出逻辑)
按照相同逻辑编写归还方法,完成库存加1操作:
public async Task<IActionResult> Return(string id) { if (id == null || _context.Books == null) { return NotFound(); } var book = await _context.Books .FirstOrDefaultAsync(m => m.BookCode == id); if (book == null) { return NotFound(); } else { // 增加库存 book.Availability = (sbyte)(book.Availability + 1); // 保存到数据库 await _context.SaveChangesAsync(); // 查询更新后的书籍列表 var updatedBooks = await _context.Books.ToListAsync(); // 返回视图并传递模型 return View("Index", updatedBooks); } }
3. 视图增加空值保护(可选但推荐)
在视图遍历前添加空值判断,避免后续类似异常:
@if (Model == null || !Model.Any()) { <tr> <td colspan="5">暂无书籍数据</td> </tr> } else { @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.Title)</td> <td>@Html.DisplayFor(modelItem => item.Author)</td> <td>@Html.DisplayFor(modelItem => item.YearPublished)</td> <td>@Html.DisplayFor(modelItem => item.BookCode)</td> <td>@Html.DisplayFor(modelItem => item.Availability)</td> <td> @if (item.Availability > 0) { <a asp-action="Loan" asp-route-id="@item.BookCode">借出</a> } <a asp-action="Return" asp-route-id="@item.BookCode">归还</a> </td> </tr> } }
优化建议(PRG模式)
如果你的Index方法已经实现了书籍列表查询逻辑,建议修改为重定向到Index方法,符合Post/Redirect/Get模式,避免重复提交问题:
// 替换Loan方法中返回视图的代码 return RedirectToAction(nameof(Index));
对应的Index方法需保证能正确传递模型:
public async Task<IActionResult> Index() { return _context.Books != null ? View(await _context.Books.ToListAsync()) : Problem("Entity set 'YourDbContext.Books' is null."); }
内容的提问来源于stack exchange,提问作者insolentmamba
相关产品推荐
相关产品推荐

