使用Entity Framework ChangeTracker处理复杂属性

时间:2012-10-18 19:20:33

标签: entity-framework asp.net-web-api audit-logging objectstatemanager

我会尝试在这篇文章中尽可能地描述。我已经阅读了十几个与我的问题外围相关的SO问题,但到目前为止还没有一个与正在发生的事情相匹配。

因此,为了对我们的数据库事务(创建,更新,删除)执行审计日志记录,我们的设计使用了一个IAuditable接口,如下所示:

public interface IAuditable
{
    Guid AuditTargetId { get; set; }

    int? ContextId1 { get; }
    int? ContextId2 { get; }
    int? ContextId3 { get; }
}

三个上下文ID与域模型的布局方式有关,并且如上所述,根据被审计的实体,它们中的一些或全部可能为空(它们用于管理员只想要的过滤目的)查看应用程序特定范围的审核日志。任何需要在CUD操作上进行审计的模型都需要实现此接口。

审计表本身的填充方式是通过位于基本DbContext和域的上下文之间的AuditableContext。它包含审计表DbSets,它使用EF ChangeTracker覆盖SaveChanges方法,如下所示:

foreach (var entry in ChangeTracker.Entries<IAuditable>())
{
    if (entry.State != EntityState.Modified && 
        entry.State != EntityState.Added && 
        entry.State != EntityState.Deleted)
    {
        continue;
    }

    // Otherwise, make audit records!
}

base.SaveChanges();

“制作审计记录”流程是一个稍微复杂的代码,使用反射和其他有趣的东西来提取需要审计的字段(可审计模型有一些方法可以让某些字段“退出”审计)以及所有这些。

所以逻辑一切都很好。当我有一个像这样的可审计模型时会出现问题:

public class Foo: Model, IAuditable
{
    public int FooId { get; set; }

    // other fields, blah blah blah...

    public virtual Bar Bar { get; set; }

    #region IAuditable members

    // most of the auditable members are just pulling from the right fields

    public int? ContextId3
    {
        get { return Bar.BarId; }
    }

    #endregion
}

正如所指出的那样,在大多数情况下,这些上下文审计字段只是模型的标准属性。但是有些情况,比如这里,需要从虚拟复杂属性中提取上下文ID。

当尝试从SaveChanges()方法中取出该属性时,最终导致NullReferenceException - 它表示虚拟Bar属性不存在。我已经阅读了一些关于如何构建ChangeTracker以允许延迟加载复杂属性的内容,但我无法找到正确的语法。这些字段不存在于“原始值”列表中,而对象状态管理器没有这些字段,我想因为它们来自接口而不是直接被审计的实体。

所以有人知道如何解决这个奇怪的问题吗?我是否可以强制加载整个对象,包括虚拟属性,而不是显然顽固的延迟加载?

对于长篇帖子感到抱歉,我觉得这是一个非常具体的问题,可能还需要详细信息。

TIA! :)

0 个答案:

没有答案