ASP.NET实现仅编辑每个车牌对应最新RoadRecord记录的方法
实现方案
需求为对RoadRecord行驶记录表做操作权限限制:仅允许用户对每个车牌号(LicencePlate)对应的最新一条记录执行编辑、删除操作,示例数据规则如下:
| Date | LicencePlate | 可编辑状态 |
|---|---|---|
| 08.19 | AAA-111 | 是 |
| 08.17 | AAA-111 | 否 |
| 08.16 | CCC-222 | 是 |
你手写的SQL查询逻辑可直接通过Entity Framework转换为业务代码,落地分三层实现,必须加后端校验避免用户通过手动拼接URL越权:
1. 数据查询层:标记记录可编辑状态
不要直接将RoadRecord实体集合传入视图,给列表视图模型新增bool CanEdit字段,通过LINQ查询直接计算每条记录的编辑权限,和你手写的SQL逻辑完全等价:
// 数据库上下文注入后执行查询 // 第一步:分组查询每个车牌对应的最新记录标识 var latestRecordMark = _context.RoadRecords .GroupBy(r => r.LicencePlate) .Select(g => new { LicencePlate = g.Key, // 若同一车牌同一天存在多条记录,优先取最大Id匹配,避免日期重复导致权限判断错误 AllowEditId = g.OrderByDescending(r => r.Date).ThenByDescending(r => r.Id).First().Id }); // 第二步:关联全量记录,赋值可编辑标识 var pageData = from record in _context.RoadRecords join mark in latestRecordMark on new { record.LicencePlate, record.Id } equals new { mark.LicencePlate, Id = mark.AllowEditId } into tempMatch from matchRes in tempMatch.DefaultIfEmpty() select new RoadRecordListVM { Id = record.Id, Date = record.Date, LicencePlate = record.LicencePlateNavigation.LicencePlate, UserName = record.User.Name, Location = record.Location, Mileage = record.Mileage, Fueling = record.Fueling, Note = record.Note, CanEdit = matchRes != null }; // 将pageData作为Model传入视图即可
如果偏好使用原生SQL,也可以直接执行你写的查询语句拿到可编辑记录的Id集合,再做全量列表的匹配标记。
2. 视图层:按权限渲染操作按钮
修改现有.cshtml的循环渲染逻辑,仅对标记为可编辑的记录展示编辑、删除入口:
<tbody> @foreach (var item in Model) { <tr class="click box-shadow" onclick="location.href = '@(Url.Action("Details", "RoadRecords", new { id = item.Id }))'"> <td>@Html.DisplayFor(modelItem => item.Date)</td> <td>@Html.DisplayFor(modelItem => item.LicencePlate)</td> <td>@Html.DisplayFor(modelItem => item.UserName)</td> <td>@Html.DisplayFor(modelItem => item.Location)</td> <td>@Html.DisplayFor(modelItem => item.Mileage)</td> <td>@Html.DisplayFor(modelItem => item.Fueling)</td> <td>@Html.DisplayFor(modelItem => item.Note)</td> <td> @if (item.CanEdit) { <a asp-action="Edit" asp-route-id="@item.Id">Szerkesztés</a> | <a asp-action="Delete" asp-route-id="@item.Id">Törlés</a> } else { <span class="text-muted">仅最新记录可编辑</span> } </td> </tr> } </tbody>
3. 接口层:强制后端权限校验
前端按钮隐藏仅做体验优化,必须在Edit、Delete的POST接口中增加权限校验,拦截越权请求:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, RoadRecord updateModel) { var currentRecord = await _context.RoadRecords.FindAsync(id); if (currentRecord == null) return NotFound(); // 查询当前车牌对应的最新记录Id var latestId = await _context.RoadRecords .Where(r => r.LicencePlate == currentRecord.LicencePlate) .OrderByDescending(r => r.Date) .ThenByDescending(r => r.Id) .Select(r => r.Id) .FirstAsync(); // 非最新记录直接返回403 if (latestId != id) return Forbid("仅允许编辑对应车牌的最新行驶记录"); // 原有编辑保存逻辑保持不变 // ... }
Delete接口复用相同校验逻辑即可。
内容的提问来源于stack exchange,提问作者kajahun123
相关产品推荐
相关产品推荐

