首先使用EF 4.2代码拦截和记录更改

时间:2011-12-01 23:15:23

标签: entity-framework entity-framework-4 ef-code-first tracking ef4-code-only

我花了一些时间阅读一些关于审计跟踪的帖子和文章,但仍然无法解决这个问题。

我需要的是一个非常基本的审计系统,它会给我以下结果:

  • 客户“John Doe”已被“用户”
  • 删除
  • 客户“Jane Doe”由“其他用户”
  • 创建
  • “John Doe”的地址被“用户”修改
  • 客户“Jane Doe”已被“其他用户”
  • 删除

我试图在dbContext上覆盖SaveChanges事件,但我遇到了以下问题:

public override int SaveChanges()
{

        foreach (DbEntityEntry<IAuditable> entry in ChangeTracker.Entries<IAuditable>())
        {
            if (entry.State == EntityState.Added)
            {
                // since the object was not added yet, if I write to log in here and
                // for some reason SaveChanges fail, I will end up with a fake log entry
            }
            else if (entry.State == EntityState.Modified)
            {
                // same in here
            }
        }

        return base.SaveChanges();

        // here the state for all entries have changed to Unchanged or Detached.
        // detached is probably the one that was deleted however the “Unchanged”
        // could be new or modified records.
}

我知道我可以在数据库上使用触发器来实现这一点,但是我想把它保留在这里,所以我对它有更多的控制权,因为我不是一个SQL人员,在部署应用程序后我不会有对数据库有很大的控制权。

我确定我在这里错过了一些非常简单的东西。 我感谢任何帮助。

提前致谢。

1 个答案:

答案 0 :(得分:2)

您可以随时检查上下文中是否有任何审核条目,并在调用SaveChanges时将其删除。它将解决您的第一个问题 - 您将始终在创建新审核条目之前将其删除。

使用DbContext API无法解决第二个问题。 DbContext API是ObjectContext API的简化,这种简化删除了复杂场景所需的方法。一种这样的方法是SaveChanges的重载版本,能够不接受更改(不更改实体的状态)。

您可以将DbContext转换为ObjectContextIObjectContextAdapter。即使使用ObjectContext,也不会是直截了当的:

// If you want to have audits in transaction with records you must handle
// transactions manually
using (TransactionScope scope = new TransactionScope(...))
{
    ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
    context.SaveChanges(SaveOptions.DetectChangesBeforeSave);

    var audits = new List<Audit>();

    // Now you must call your audit code but instead of adding audits to context
    // you must add them to list. 

    // This is the reason why you must not add changes to context. You must accept
    // old changes prior to adding your new audit records otherwise EF will perform
    // changes again. If you add your entities to context and call accept before 
    // saving them your changes will be lost
    context.AcceptAllChanges();

    // Now add all audits from list to context

    context.SaveChanges();

    // Complete the transaction
    scope.Complete(); 
}