如何从实体框架 6 中的 Auditlog 实体获取 id

Posted

技术标签:

【中文标题】如何从实体框架 6 中的 Auditlog 实体获取 id【英文标题】:How to get id from entity for Auditlog in Entity Framework 6 【发布时间】:2013-11-16 20:21:30 【问题描述】:

我知道那里有几个类似的帖子,但我找不到任何可以解决此问题的帖子。

我想在 Entity Framework 6 中添加、更改或删除实体(软删除)时添加(某种)AudioLog。我已经覆盖了 SaveChanges,因为我只想为 EntityStates 添加、修改添加日志条目或已删除,我在第一次调用 SaveChanges 之前获取列表。问题是,因为我需要记录已执行的操作,所以我需要检查实体的 EntityState。但是在调用 SaveChanges 之后,EntityState 对于所有条目都是 Unchanged。

public override int SaveChanges()

    using (var scope = new TransactionScope())
    
        var modifiedEntries = ChangeTracker.Entries()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Deleted || e.State == EntityState.Modified)
            .ToList();

        int changes = base.SaveChanges();
        foreach (var entry in modifiedEntries)
        
            ApplyAuditLog(entry);
        

        base.SaveChanges();
        scope.Complete();
        return changes;
    


private void ApplyAuditLog(DbEntityEntry entry)

    ILog entity = entry.Entity as ILog;

    if (entity != null)
    
        LogOperation operation;
        switch (entry.State)
        
            case EntityState.Added:
                operation = LogOperation.CreateEntity;
                break;
            case EntityState.Deleted:
                operation = LogOperation.DeleteEntity;
                break;
            case EntityState.Modified:
                operation = LogOperation.UpdateEntity;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        

        AuditLog log = new AuditLog
        
            Created = DateTime.Now,
            Entity = entry.Entity.GetType().Name,
            EntityId = entity.Id,
            Operation = operation,
        ;

        AuditLog.Add(log);
    

【问题讨论】:

如果 id 是数据库生成的,那么您需要在 SaveChanges() 调用之后检索它,因为之前的 id 根本不存在。 如果您查看代码,这正是我所做的。这不是问题,是在 SaveChanges 之后 EntityState 发生了变化。 对不起,我忽略了这一点。保存后 EntityState 将更改,因为 EntityState 不再添加或修改 - 它未修改。因此,如果您想保留 EntityState,则必须在保存之前存储该数据 - 并在保存后检索 id。 我知道。但我希望有人有一个很好的方法来解决这个问题。由于我在 SaveChanges() 之前没有 id,因此我无法弄清楚如何在第一个 SaveChanges() 之后将正确的 id 映射到正确的 AuditLog 对象。我需要依赖每个元素的索引位置吗?还是有更清洁的选择?如果是这样,请提供一个例子。 【参考方案1】:

啊……当然了!!对于新添加的实体,id 只会是一个“问题”,因此通过将列表分成两个(一个用于修改/删除,一个用于添加),我分两个阶段创建 AuditLog。

对于其他想要应用这种 AuditLog 的人,这是我的工作代码:

public override int SaveChanges()

    using (var scope = new TransactionScope())
    
        var addedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Added).ToList();
        var modifiedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted || e.State == EntityState.Modified).ToList();

        foreach (var entry in modifiedEntries)
        
            ApplyAuditLog(entry);
        

        int changes = base.SaveChanges();
        foreach (var entry in addedEntries)
        
            ApplyAuditLog(entry, LogOperation.CreateEntity);
        

        base.SaveChanges();
        scope.Complete();
        return changes;
    


private void ApplyAuditLog(DbEntityEntry entry)

    LogOperation operation;
    switch (entry.State)
    
        case EntityState.Added:
            operation = LogOperation.CreateEntity;
            break;
        case EntityState.Deleted:
            operation = LogOperation.DeleteEntity;
            break;
        case EntityState.Modified:
            operation = LogOperation.UpdateEntity;
            break;
        default:
            throw new ArgumentOutOfRangeException();
    

    ApplyAuditLog(entry, operation);


private void ApplyAuditLog(DbEntityEntry entry, LogOperation logOperation)

    ILog entity = entry.Entity as ILog;

    if (entity != null)
    
        AuditLog log = new AuditLog
        
            Created = DateTime.Now,
            Entity = entry.Entity.GetType().Name,
            EntityId = entity.Id,
            Operation = logOperation,
        ;
        AuditLog.Add(log);
    

【讨论】:

您可能希望将 SaveChanges 包装在 try/throw 中以捕获异常并退出审核条目。如果提交失败,审计条目不应该存在 其实添加时需要id,审计必须和原表相关,以备查。 你为什么使用 2 foreach ?相反,你可以做一次【参考方案2】:

您可以将 EntityState 保存到 Entity 键值对并在第一次更改后使用它。

var 条目 = this.ChangeTracker.Entries() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) .Select(e => new e.State, e ).ToList();

【讨论】:

请更正您的回复Editing Help 的格式,并确保您的问题回答了原作者的问题。 请阅读How to answer 并更新您的答案。

以上是关于如何从实体框架 6 中的 Auditlog 实体获取 id的主要内容,如果未能解决你的问题,请参考以下文章

从数据库优先实体框架 6.2 中的 SaveChanges 中删除标识列

从实体框架中的集合加载相关实体

实体框架6不适用于Temporal表

从一个 id 更新实体框架中的多行

从 id 列表更新实体框架中的多行

EF 6.X 中的实体框架代码优先 Fluent API 默认值