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

Entity Framework修改记录时丢失CreatedOn等审计数据的问题

解决ASP.NET Core Web API中EF Core+SQLite修改记录时CreatedBy/CreatedOn丢失的问题

问题原因

当修改实体时,如果CreatedOn、CreatedBy字段在当前被跟踪的实体实例中未保留原有值(比如通过DTO映射实体时未传递这两个字段),EF Core会将这些字段的当前默认值(通常为null)更新到数据库,从而覆盖原有有效值。

解决方案

方案一:在SaveChangesAsync中锁定Created字段的修改状态

修改重写的SaveChangesAsync方法,对处于Modified状态的实体,强制将CreatedOn、CreatedBy字段的修改状态设为false,确保数据库中原有值不会被覆盖:

private readonly IHttpContextAccessor _contextAccessor;

public EvaDbContext(DbContextOptions options, IHttpContextAccessor contextAccessor) : base(options)
{
    _contextAccessor = contextAccessor;
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
    if (!_contextAccessor.IsLoginRequeust())
    {
        var entityEntries = ChangeTracker.Entries()
            .Where(e => e.Entity is DomainObject && (e.State == EntityState.Added || e.State == EntityState.Modified));
        var userId = _contextAccessor.GetUserId();

        foreach (var entityEntry in entityEntries)
        {
            var domainObj = (DomainObject)entityEntry.Entity;
            
            if (entityEntry.State == EntityState.Modified)
            {
                // 更新修改审计字段
                domainObj.ModifiedOn = DateTime.Now;
                domainObj.ModifiedBy = userId;

                // 锁定Created字段,禁止修改
                entityEntry.Property(nameof(DomainObject.CreatedOn)).IsModified = false;
                entityEntry.Property(nameof(DomainObject.CreatedBy)).IsModified = false;
            }
            else if (entityEntry.State == EntityState.Added)
            {
                // 设置新增审计字段
                domainObj.CreatedOn = DateTime.Now;
                domainObj.CreatedBy = userId;
                domainObj.ModifiedOn = DateTime.Now;
                domainObj.ModifiedBy = userId;
            }
        }
    }

    return await base.SaveChangesAsync(cancellationToken);
}

方案二:配置实体属性为仅新增时赋值

在OnModelCreating方法中,对CreatedOn、CreatedBy字段进行配置,明确其仅在插入时生效,修改时忽略:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<DomainObject>()
        .Property(x => x.CreatedOn)
        .ValueGeneratedOnAdd(); // 仅在插入时处理值,修改时忽略

    modelBuilder.Entity<DomainObject>()
        .Property(x => x.CreatedBy)
        .ValueGeneratedOnAdd(); // 标记为仅插入时赋值,修改时EF会忽略该字段变化
}

方案三:采用"获取实体+局部更新"的业务逻辑

在业务代码中,避免直接调用Update方法更新整个实体,而是先从数据库查询出目标实体,仅修改需要更新的字段:

public async Task UpdateEntity(int entityId, UpdateEntityDto dto)
{
    var targetEntity = await _dbContext.DomainObjects.FindAsync(entityId);
    if (targetEntity == null)
    {
        throw new ArgumentException("实体不存在");
    }

    // 仅更新需要修改的字段
    targetEntity.Title = dto.Title;
    targetEntity.Content = dto.Content;

    await _dbContext.SaveChangesAsync();
}

这种方式下,EF Core只会跟踪被修改的字段,CreatedOn、CreatedBy会保持数据库中的原有值,不会被覆盖。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:05:11