aierda 2023-05-26 11:45 采纳率: 76%
浏览 75
已结题

数据修改之后EntityState.Unchanged还是true

背景说明:我使用的后端是ABP,里面的数据库操作用的是EF Core.
我希望每次的数据变化,比如新增、修改、删除都记录到一个表(Audit)里面去.
之前已经实现效果了,但是这两天发现对数据的修改,根本不会写入到Audit表。
不知道问题出在哪里。数据保存是没有问题,但是就是无法记录修改部分。
大致的代码如下

private readonly IRepository<User, Guid> _userRepository;
。
。
。
User user = ObjectMapper.Map<User>(userDto);
//修改用户表中的某条记录
await _userRepository.UpdateAsync(user);
//使用DbContext().SaveChanges(),触发数据库变化事件
_userRepository.GetDbContext().SaveChanges();

然后在DBContext类中会接收数据变化事件

//数据变化,都会被这个方法拦截
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
    AuditList = new List<Audit>();
    var auditEntries = OnBeforeSaveChanges();
    var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    await OnAfterSaveChanges(auditEntries);
    return result;
}
private List<AuditEntry> OnBeforeSaveChanges()
{
    ChangeTracker.DetectChanges(); //捕获各个表数据的变化
    var auditEntries = new List<AuditEntry>();
    foreach (var entry in ChangeTracker.Entries())
    {
        //如果变数据没有发生实际的变化,则会continue; 但是目前的情况是,
        //尽管数据发生了变化,entry.State依然是Unchanged,所以导致无法记录修改内容
        if (entry.Entity is Audit || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged)
            continue;

        var auditEntry = new AuditEntry(entry);
        auditEntry.TableName = entry.Metadata.GetTableName();
        auditEntries.Add(auditEntry);

        foreach (var property in entry.Properties)
        {
            。。。 //对变化属性值的处理
        }
    }

    // Save audit entities that have all the modifications
    foreach (var auditEntry in auditEntries.Where(_ => !_.HasTemporaryProperties))
    {
        Audits.Add(auditEntry.ToAudit());
    }

    // keep a list of entries where the value of some properties are unknown at this step
    return auditEntries.Where(_ => _.HasTemporaryProperties).ToList();
}

问题就出现在
if (entry.Entity is Audit || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged)
continue;
中,数据修改之后EntityState.Unchanged还是true,正常情况是false才对,这样才能继续往下走,
继而记录数据变化部分

我的提问:会是什么原因导致,数据实际变化了,但是却捕获不到呢?有什么解决方案吗?
恳请大家帮忙指点,感谢!

  • 写回答

7条回答 默认 最新

  • 鱼弦 全栈领域优质创作者 2023-05-26 13:54
    关注

    出现这种情况的原因可能是因为EF Core的Change Tracker没有正确地跟踪实体的状态变化,导致无法正确地检测到实体的修改。这可能与一些因素有关,例如:

    可能在修改实体后没有调用DbContext.SaveChanges()方法,导致EF Core无法正确跟踪实体状态的变化。
    可能实体的状态被手动更改为EntityState.Unchanged,从而导致EF Core无法正确检测到实体的修改。
    可能在修改实体时,只是修改了导航属性,而没有修改实体本身的属性,从而导致EF Core无法正确检测到实体的修改。
    为了解决这个问题,你可以尝试以下方法:

    确保在修改实体后,调用DbContext.SaveChanges()方法,以便让EF Core正确地跟踪实体状态的变化。
    在修改实体时,不要手动更改实体的状态为EntityState.Unchanged,让EF Core自动跟踪实体状态的变化。
    如果实体的修改只涉及到导航属性的修改,而没有修改实体本身的属性,可以尝试手动更改实体的状态,以便EF Core正确地跟踪实体状态的变化。例如:

    // 修改实体的导航属性
    user.Role = newRole;
    
    // 手动将实体状态设置为Modified
    _userRepository.GetDbContext().Entry(user).State = EntityState.Modified;
    
    // 保存修改
    _userRepository.GetDbContext().SaveChanges();
    
    

    这样,即使实体的修改只涉及到导航属性的修改,EF Core也能正确地检测到实体状态的变化,并记录到Audit表中。

    另外,还可以在修改实体时,使用DbContext.Entry()方法获取实体的状态信息,以便更好地跟踪实体状态的变化。例如:

    // 获取实体的状态信息
    var entry = _userRepository.GetDbContext().Entry(user);
    entry.State = EntityState.Modified;
    
    
    
    // 保存修改
    _userRepository.GetDbContext().SaveChanges();
    
    

    这样,即使实体的状态发生了变化,EF Core也能正确地检测到实体状态的变化,并记录到Audit表中。

    方案二:

    在 EF Core 中,当您执行更新操作时,EF Core 会自动检测哪些属性已更改,并将其标记为 "Modified"。但是在某些情况下,这种检测可能无法正常工作,导致 EF Core 将实体状态标记为 "Unchanged",即使实体的属性已更改。

    这种情况可能发生在以下情况下:

    某些属性的值未更改,但是它们的状态已更改为 "Modified"。

    在更改实体属性之前,另一个操作已更改了与该实体相关的数据,因此 EF Core 无法正确检测到属性的更改。

    解决此问题的一种方法是手动将实体状态标记为 "Modified"。您可以尝试在更新操作之前手动标记实体状态。例如:

    csharp
    Copy
    _userRepository.GetDbContext().Entry(user).State = EntityState.Modified;
    这将强制 EF Core 将实体状态标记为 "Modified",即使属性的状态未更改。

    另外,您可以尝试使用 DbContext.Update() 方法替代 _userRepository.UpdateAsync() 方法,因为 DbContext.Update() 方法可以自动将实体状态标记为 "Modified"。例如:

    csharp
    Copy
    _userRepository.GetDbContext().Update(user);
    这将自动将实体状态标记为 "Modified",并且在调用 SaveChanges() 方法时,EF Core 将正确检测到实体属性的更改,并将其记录到 Audit 表中。

    如果您仍然遇到问题,您可以尝试在 SaveChanges() 方法中打印出所有实体的状态,以便更好地了解 EF Core 如何处理它们。例如:

    csharp
    Copy
    foreach (var entry in ChangeTracker.Entries())
    {
    Console.WriteLine($"{entry.Entity.GetType().Name} - {entry.State}");
    }
    这将输出每个实体的类型和状态。如果某个实体的状态不符合预期,请检查该实体的更改是否正确地标记为 "Modified",或者是否有其他操作已更改了该实体的状态。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(6条)

报告相同问题?

问题事件

  • 系统已结题 6月7日
  • 已采纳回答 5月30日
  • 创建了问题 5月26日

悬赏问题

  • ¥15 一个识别内容的自动化脚本程序
  • ¥15 anaconda虚拟python环境部署langchain-chatchat报错
  • ¥20 matlab有约束条件下的多元函数求最小值
  • ¥50 如何隐藏网页弹出框的url地址栏
  • ¥20 metropolis算法模拟二维ising模型来计算磁化强度,fortran
  • ¥15 uniapp-typescript-vue报错
  • ¥15 oracle强制关机以后报错01033
  • ¥15 给Chat with RTX添加语言模型时遇到问题
  • ¥15 oracle修复,怎么根据日志修复呀?
  • ¥15 使用Stable Diffusion时出现错误