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

Entity Framework 6 中自动创建实体历史表的实现方法

嘿,刚上手EF6要做全实体的历史记录是吧?这需求太常见了,我给你分享几个实用的方案,从原生实现到第三方工具都有,你可以根据自己的项目情况选:

方案一:重写DbContext的SaveChanges(原生实现,无依赖)

这是最灵活的方式,不用加任何第三方库,完全自己控制逻辑:

步骤1:定义通用的历史表实体

先创建一个EntityHistory类,用来存储所有实体的变更记录:

public class EntityHistory
{
    public int Id { get; set; }
    public string EntityName { get; set; } // 变更的实体类名(比如"User"、"Order")
    public string EntityId { get; set; } // 变更实体的主键值
    public DateTime ChangedAt { get; set; } // 变更时间
    public string ChangedBy { get; set; } // 操作人(可以从当前用户获取)
    public string OldValues { get; set; } // 变更前的旧值(用JSON序列化存储)
    public string ChangeType { get; set; } // 操作类型:Insert/Update/Delete
}

步骤2:在你的DbContext里重写SaveChanges方法

在继承DbContext的类里,覆盖SaveChanges方法,捕获所有变更的实体并写入历史表:

using Newtonsoft.Json; // 需要安装Newtonsoft.Json NuGet包

public class YourDbContext : DbContext
{
    // 注册历史表DbSet
    public DbSet<EntityHistory> EntityHistories { get; set; }

    public override int SaveChanges()
    {
        // 获取所有状态为新增、修改、删除的实体
        var changedEntries = ChangeTracker.Entries()
            .Where(e => e.State is EntityState.Added or EntityState.Modified or EntityState.Deleted);

        foreach (var entry in changedEntries)
        {
            var historyRecord = new EntityHistory
            {
                EntityName = entry.Entity.GetType().Name,
                ChangedAt = DateTime.Now,
                ChangedBy = HttpContext.Current?.User?.Identity?.Name ?? "Unknown", // 适配ASP.NET场景
                ChangeType = entry.State.ToString()
            };

            // 获取实体主键值(假设所有实体都有名为Id的主键,通用场景可以用反射获取主键)
            var primaryKey = entry.Property("Id").CurrentValue;
            historyRecord.EntityId = primaryKey?.ToString() ?? "N/A";

            // 处理旧值:新增没有旧值,修改和删除序列化原始值
            if (entry.State != EntityState.Added)
            {
                historyRecord.OldValues = JsonConvert.SerializeObject(entry.OriginalValues.ToObject());
            }

            // 将历史记录添加到上下文
            EntityHistories.Add(historyRecord);
        }

        // 先保存历史记录,再保存主实体变更
        return base.SaveChanges();
    }
}

步骤3:生成历史表

用EF Code-First迁移生成数据库表:

  1. 打开Package Manager Console
  2. 执行 Add-Migration AddEntityHistoryTable
  3. 执行 Update-Database
方案二:用Audit.NET快速实现(第三方工具,省心省力)

如果不想自己写太多代码,Audit.NET是专门做审计记录的成熟库,对EF6支持很好:

步骤1:安装NuGet包

Install-Package Audit.EntityFramework

步骤2:配置Audit.NET

在项目启动的地方(比如Global.asax的Application_Start)配置审计规则:

using Audit.Core;
using Audit.EntityFramework;
using Newtonsoft.Json;

Audit.Core.Configuration.Setup()
    .UseEntityFramework(options => options
        // 指定审计记录对应的实体类
        .AuditTypeMapper(_ => typeof(EntityHistory))
        // 映射审计事件到EntityHistory字段
        .AuditEntityAction<EntityHistory>((auditEvent, dbEntry, historyEntity) =>
        {
            historyEntity.EntityName = dbEntry.EntityType.Name;
            historyEntity.EntityId = dbEntry.PrimaryKey.First().Value.ToString();
            historyEntity.ChangedAt = DateTime.Now;
            historyEntity.ChangedBy = HttpContext.Current?.User?.Identity?.Name ?? "Unknown";
            historyEntity.ChangeType = dbEntry.Action;
            historyEntity.OldValues = dbEntry.OldValues != null 
                ? JsonConvert.SerializeObject(dbEntry.OldValues) 
                : null;
        })
        // 忽略和EntityHistory实体匹配的属性(避免循环引用)
        .IgnoreMatchedProperties());

步骤3:修改DbContext继承AuditDbContext

把你的DbContext改成继承AuditDbContext:

public class YourDbContext : AuditDbContext
{
    // 你的其他DbSet...
    public DbSet<EntityHistory> EntityHistories { get; set; }

    public YourDbContext() : base("YourConnectionString")
    {
    }
}

这样每次调用SaveChanges,Audit.NET会自动帮你生成历史记录,不用自己写拦截逻辑。

注意事项
  • 主键通用处理:如果你的实体主键不是叫Id,方案一里需要用反射动态获取主键字段,比如通过entry.Metadata.FindPrimaryKey()来获取主键属性。
  • 性能优化:如果是高并发场景,批量写入历史记录可以提升性能,比如把历史记录先缓存,定时批量插入。
  • 敏感数据:如果实体包含敏感信息(比如密码),序列化的时候要排除这些字段,避免泄露。

内容的提问来源于stack exchange,提问作者Josef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:16:44