如何在Audit.NET的OnEventSaved事件中获取刚保存的AuditLog表主键
问题解答
1. 当前实现的安全性问题
当前通过取最大ID的实现方式完全不安全,存在以下明确问题:
- 高并发场景下必然出现主键错配:多个请求同时插入AuditLog时,
OrderByDescending取最大ID会拿到其他请求刚插入的主键,导致明细关联到错误的审计日志 - 存在空引用异常风险:如果
FirstOrDefault()返回null(比如审计日志插入失败、上下文无对应数据),直接访问.Id会抛出空引用异常 - 额外增加不必要的数据库查询开销,性能较差
2. 更优实现方案
不需要查询数据库,Audit.NET的EF事件已经内置了本次操作所有实体的元数据,包括插入后自动生成的主键,直接从事件对象中取值即可:
public void ConfigureAuditDetail(AuditScope scope) { var efEvent = (scope.Event as AuditEventEntityFramework)?.EntityFrameworkEvent; if (efEvent == null) return; // 从本次操作的实体条目中筛选出刚插入的AuditLog实体 var auditLogEntry = efEvent.Entries .FirstOrDefault(e => e.Action == "Insert" && e.EntityType == typeof(AuditLog).FullName); if (auditLogEntry == null) return; // 直接获取已生成的主键,无数据库查询 var auditLogId = (int)auditLogEntry.PrimaryKey.First().Value; // 后续明细保存逻辑 // ... }
如果你的AuditLog是单独插入、不在当前EF事件的Entries中,可以在插入AuditLog时就把生成的ID存入AuditScope的自定义字段,后续直接读取即可:
// 插入AuditLog的逻辑位置 using(var scope = AuditScope.Create("Operation", () => new { /* 自定义字段 */ })) { // 插入AuditLog获取ID后存入自定义字段 scope.SetCustomField("AuditLogId", newAuditLog.Id); // 其他业务逻辑 } // ConfigureAuditDetail中直接读取 var auditLogId = scope.Event.CustomFields.TryGetValue("AuditLogId", out var idVal) ? (int)idVal : 0;
内容的提问来源于stack exchange,提问作者Tango Down
相关产品推荐
相关产品推荐

