.NET实现字段变更记录
简介
有时候在开发中,需要对实体的某个字段做变更日志,如果显式保存日志,会对业务代码耦合太大。
本文采用重写DbContext的SaveChanges方法实现,在指定字段变更时,自动添加变更日志,减少对业务代码的耦合。
实体定义
ToDoItem是主实体,ToDoItemTextLog是ToDoItem的Text字段的变更记录
public class ToDoItem : FullAuditedEntity<long>
{
public string Text { get; set; }
}
public class ToDoItemTextLog : FullAuditedEntity<long>
{
public long ToDoItemId { get; set; }
[ForeignKey(nameof(ToDoItemId))]
public ToDoItem ToDoItem { get; set; }
public string NewValue { get; set; }//新值
public string OriginalValue { get; set; }//旧值
}
在项目的DbContext类中,增加一个方法
protected virtual ICollection<ToDoItemTextLog> ChangeToDoItemTextLog()
{
//获取跟踪的实体
var entries = ChangeTracker.Entries().ToList();
//定义数组
var logs = new List<ToDoItemTextLog>();
foreach (var entry in entries)
{
//如果该实体是ToDoItem,并且是被修改的状态
if (entry.Entity is ToDoItem toDoItem && entry.State == EntityState.Modified)
{
//获取Text字段的新旧值,并存入数组
//var properties = entry.Metadata.GetProperties();
var propEntry = entry.Property("Text");
logs.Add(new ToDoItemTextLog()
{
ToDoItemId = toDoItem.Id,
NewValue = propEntry.CurrentValue.ToString(),
OriginalValue = propEntry.OriginalValue.ToString(),
});
}
}
return logs;
}
重写DbContext的SaveChanges和SaveChangesAsync
保存变更记录数组的代码需要放在base.SaveChanges()之前
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
// ……其他本文无关代码
// 获取变更记录的数组
var toDoItemTextLogs = ChangeToDoItemTextLog();
if (toDoItemTextLogs.Count > 0)
// 开启事务
using (var tran = Database.BeginTransaction())
{
// 将该数组存入数据库
AddRange(toDoItemTextLogs);
tran.Commit();
}
// ……其他本文无关代码
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
// ……其他本文无关代码
var toDoItemTextLogs = ChangeToDoItemTextLog();
if (toDoItemTextLogs.Count > 0)
using (var tran = await Database.BeginTransactionAsync(cancellationToken))
{
AddRange(toDoItemTextLogs);
await tran.CommitAsync(cancellationToken);
}
// ……其他本文无关代码
}