You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:08:28