如何修改Auditable类实现不同表审计字段的动态带前缀列名
适配不同表前缀的审计字段解决方案
针对不同表需要带专属前缀的审计字段需求,我们可以通过自定义特性+反射赋值的方式替换原有的固定字段基类方案,具体实现如下:
1. 定义审计字段标记特性
首先创建特性类,用来标记实体属性对应的审计类型:
[AttributeUsage(AttributeTargets.Property)] public class AuditFieldAttribute : Attribute { public AuditFieldType FieldType { get; } public AuditFieldAttribute(AuditFieldType fieldType) { FieldType = fieldType; } } public enum AuditFieldType { CreatedBy, CreatedDate, ModifiedBy, ModifiedDate }
2. 实体类定义带前缀的审计字段
每个表的实体类自行定义带专属前缀的审计字段,并通过AuditField特性标记对应的审计类型:
// TN1表实体示例 public class TN1Entity { // 业务字段... [AuditField(AuditFieldType.CreatedBy)] public decimal? TN1_CreatedBy { get; set; } [AuditField(AuditFieldType.CreatedDate)] public DateTime? TN1_CreatedDate { get; set; } [AuditField(AuditFieldType.ModifiedBy)] public decimal? TN1_ModifiedBy { get; set; } [AuditField(AuditFieldType.ModifiedDate)] public DateTime? TN1_ModifiedDate { get; set; } } // TN2表实体示例 public class TN2Entity { // 业务字段... [AuditField(AuditFieldType.CreatedBy)] public decimal? TN2_CreatedBy { get; set; } [AuditField(AuditFieldType.CreatedDate)] public DateTime? TN2_CreatedDate { get; set; } [AuditField(AuditFieldType.ModifiedBy)] public decimal? TN2_ModifiedBy { get; set; } [AuditField(AuditFieldType.ModifiedDate)] public DateTime? TN2_ModifiedDate { get; set; } }
3. 修改SaveChanges方法实现自动赋值
重写SaveChanges时,遍历所有实体条目,通过反射识别带AuditField特性的属性,根据实体状态和审计类型自动赋值:
public override int SaveChanges() { decimal? loggedinUserId = null; if (_httpContext.Items["USER"] != null) { var userInfo = _httpContext.Items["USER"]; var idProp = userInfo.GetType().GetProperty("Id"); if (idProp != null) { loggedinUserId = (decimal?)idProp.GetValue(userInfo); } } foreach (var entry in ChangeTracker.Entries()) { if (entry.State != EntityState.Added && entry.State != EntityState.Modified) continue; var auditProperties = entry.Entity.GetType() .GetProperties() .Where(p => p.GetCustomAttribute<AuditFieldAttribute>() != null); foreach (var prop in auditProperties) { var auditAttr = prop.GetCustomAttribute<AuditFieldAttribute>(); if (auditAttr == null) continue; switch (auditAttr.FieldType) { case AuditFieldType.CreatedBy: if (entry.State == EntityState.Added && loggedinUserId.HasValue) prop.SetValue(entry.Entity, loggedinUserId); break; case AuditFieldType.CreatedDate: if (entry.State == EntityState.Added) prop.SetValue(entry.Entity, DateTime.Now); break; case AuditFieldType.ModifiedBy: if (entry.State == EntityState.Modified && loggedinUserId.HasValue) prop.SetValue(entry.Entity, loggedinUserId); break; case AuditFieldType.ModifiedDate: if (entry.State == EntityState.Modified) prop.SetValue(entry.Entity, DateTime.Now); break; } } } return base.SaveChanges(); }
方案优势
- 完全适配不同表的前缀需求,实体字段命名灵活,不受基类固定字段限制
- 审计逻辑与实体字段解耦,新增实体时只需添加带特性的字段,无需修改保存逻辑
- 反射逻辑简洁高效,仅针对有审计标记的属性处理,性能影响可忽略
内容的提问来源于stack exchange,提问作者smilu
相关产品推荐
相关产品推荐

