EF Core时态表能否禁用更新历史仅保留删除记录?
EF Core时态表仅保留删除记录的实现方案
默认情况下,EF Core启用的SQL Server系统版本时态表会自动跟踪所有行的更新、删除操作并记录到历史表中,无法通过IsTemporal()的原生配置直接实现仅保留删除记录的需求。不过可以通过以下两种方式达到目标:
方式一:自定义删除记录存储(推荐)
放弃系统时态表的自动跟踪,手动实现删除记录的持久化,有两种实现思路:
1. 在EF Core中重写SaveChanges捕获删除操作
通过重写DbContext的SaveChanges或SaveChangesAsync方法,在保存更改时捕获被删除的实体,将其复制到自定义的历史表中:
public class AppDbContext : DbContext { public DbSet<UserModel> Users { get; set; } public DbSet<UserDeleteHistory> UserDeleteHistories { get; set; } // 重写同步保存方法 public override int SaveChanges() { // 捕获所有被标记为删除的UserModel实体 var deletedUsers = ChangeTracker.Entries<UserModel>() .Where(e => e.State == EntityState.Deleted) .Select(e => e.Entity) .ToList(); // 将删除记录插入自定义历史表 foreach (var user in deletedUsers) { UserDeleteHistories.Add(new UserDeleteHistory { UserId = user.Id, UserName = user.Name, Email = user.Email, DeleteTime = DateTime.UtcNow // 按需复制其他需要保留的属性 }); } return base.SaveChanges(); } // 重写异步保存方法 public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { var deletedUsers = ChangeTracker.Entries<UserModel>() .Where(e => e.State == EntityState.Deleted) .Select(e => e.Entity) .ToList(); foreach (var user in deletedUsers) { UserDeleteHistories.Add(new UserDeleteHistory { UserId = user.Id, UserName = user.Name, Email = user.Email, DeleteTime = DateTime.UtcNow }); } return await base.SaveChangesAsync(cancellationToken); } } // 自定义删除历史实体 public class UserDeleteHistory { public int Id { get; set; } public int UserId { get; set; } public string UserName { get; set; } public string Email { get; set; } public DateTime DeleteTime { get; set; } }
2. 数据库层面创建DELETE触发器
在SQL Server的Users表上创建DELETE触发器,当执行删除操作时自动将被删除的行插入到自定义历史表,这种方式不受数据操作方式限制(EF、原生SQL语句等都能触发):
-- 先创建自定义删除历史表 CREATE TABLE UserDeleteHistory ( Id INT, Name NVARCHAR(255), Email NVARCHAR(255), DeleteTime DATETIME DEFAULT GETUTCDATE() -- 按需添加其他需要保留的字段 ); -- 创建删除触发器 CREATE TRIGGER trg_Users_AfterDelete ON Users AFTER DELETE AS BEGIN SET NOCOUNT ON; INSERT INTO UserDeleteHistory (Id, Name, Email) SELECT Id, Name, Email FROM DELETED; END;
方式二:保留系统时态表,定时清理更新记录
如果必须使用系统时态表,可以在启用后通过定时任务清理历史表中的更新记录:
系统时态表的历史记录中,更新操作产生的记录对应的主表中仍存在该行数据(即历史表的Id在主表Users中可找到),而删除操作产生的记录对应的主表数据已不存在。可以基于这个逻辑编写清理脚本:
-- 清理Users历史表中属于更新操作的记录 DELETE FROM UsersHistory WHERE Id IN (SELECT Id FROM Users);
将该脚本配置为定时任务(比如SQL Server代理作业),定期执行即可只保留删除产生的历史记录。
内容的提问来源于stack exchange,提问作者Gabriel Ribeiro Rossi
相关产品推荐
相关产品推荐

