【问题标题】:Entity Framework 6 (code first) entity versioning and auditingEntity Framework 6(代码优先)实体版本控制和审计
【发布时间】:2015-02-20 11:16:20
【问题描述】:

我正在考虑将 Entity Framework 6.1.1 与 SQL Server 2008 R2 结合使用。

目前我正在使用代码优先 EF 功能创建模型和数据库。我的基本用例是创建对特定实体的所有更改的日志(ID 是关键列),以帮助审计员跟踪所做的所有更改以及由谁进行的更改。例如:

|ID|Version|Created Date|Created By|Modified Date|Modified By|Modify Action| ... (rest of entity fields)
-------------------------------------------------------------------------------------------------------
| 4| 12    | 12-Mar-14  | tom      | 20-Feb-15   | jack      | Update      |
| 4| 11    | 12-Mar-14  | tom      | 14-Feb-15   | jill      | Update      |
| 4| 1     | 12-Mar-14  | tom      | 12-Mar-14   | tom       | Create      |

Entity Framework 是否支持这种类型的数据库方案?如果是这样,我该如何设置我的模型/解决方案来促进这一点?

我的另一种选择是拦截对DbContext 上的SaveChanges() 方法的所有调用,并将所有数据库更改记录到单独的Audit 表中,但这可能会使检索信息更具挑战性。

任何有关使用 SQL Server 和 EF 6 创建审计跟踪的帮助将不胜感激。

【问题讨论】:

标签: c# sql-server entity-framework entity-framework-6


【解决方案1】:

我使用了你提到的第二种方法,通过重载 dbContext SaveChanges() 方法:

public class MyContext : DbContext
{

 public int SaveChanges(int userId)
 {
    // Get all Added/Deleted/Modified entities (not Unmodified or Detached)
    foreach (var ent in this.ChangeTracker.Entries().Where(p => p.State ==  EntityState.Added 
    || p.State == EntityState.Deleted || p.State == EntityState.Modified))
    {

        foreach (AuditLog x in GetAuditRecordsForChange(ent, userId))
        {
            this.AuditLogs.Add(x);
        }
    }
    return base.SaveChanges();
  }
...

所以如果我想记录一个特定的实体,我只需调用重载的 SaveChanges 并传入一个 UserId:

public void Update(StockCatalogueItem entity, int userId)
{
     _context.SaveChanges(userId);
}

我还有一个自定义的DoNotLog 属性,我用它来装饰我不想记录的实体属性。如果没有这个,日志记录可能会生成大量数据,因为每个实体修改都等于一个数据库条目。

[DoNotLog]
public int CreatedBy { get; set; }

GetAuditRecordsForChange 方法检查任何DoNotLog 属性并返回一个List<AuditLog>,该List<AuditLog> 保存在 AuditLogs 表中:

public class AuditLog
    {
        public int Id { get; set; }
        public int CreatedBy { get; set; }
        public DateTime CreatedOn { get; set; }
        public AuditEventType EventType { get; set; }
        public string TableName { get; set; }
        public int EntityId { get; set; }
        public string ColumnName { get; set; }
        public string Controller { get; set; }
        public string Action { get; set; }
        public string IPAddress { get; set; }
        public string OriginalValue { get; set; }
        public string NewValue { get; set; }
    }

【讨论】:

    【解决方案2】:

    您可以查看Entity Framework Extended。它具有审计功能,我用它来记录对 XML 实体的所有更改。来自文档:

    审核日志功能将随时捕获对实体的更改 它们被提交到数据库。审核日志仅捕获 已更改的实体以及这些实体上的属性 那被改变了。记录之前和之后的值。 AuditLogger.LastAudit 是保存此信息的位置,并且有 ToXml() 方法可以轻松地将 AuditLog 转换为 xml 易于存储。

    可以通过实体上的属性或通过 Fluent 配置 API。

    更新:

    自 2015 年起不再支持扩展实体框架。 此功能请参考Entity Framework Plus

    【讨论】:

      【解决方案3】:

      我会说这是 DDD 架构中提到的事件溯源模式的一个很好的候选者。你永远不会改变你的实体表,但总是插入。

      这样,当您需要特定版本时,您只需重新播放所有事件并将它们应用于从版本 0 到您正在寻找的版本的实体。可扩展性可以通过实体快照来解决。

      第二种方法也有效。

      参考: http://microservices.io/patterns/data/event-sourcing.html

      【讨论】:

        猜你喜欢
        • 2021-05-04
        • 1970-01-01
        • 1970-01-01
        • 2014-01-20
        • 1970-01-01
        • 2016-11-03
        • 2020-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多