问题 NHibernate在保存时自动设置属性


我正在使用DDD和NHibernate来持久保存我的域对象。在我的数据库中,每个与实体相关的表都有四个用于审计跟踪的额外列(CreatedBy,UpdatedBy,CreatedDate,UpdatedDate)。我使用的存储库模式只允许保存聚合根。当NHibernate尝试在聚合根上保存实体时,我收到SQL DateTime错误,因为实体没有设置其审计属性。 NHibernate中是否有一种方法可以在保存之前设置对象的属性?

这是一个小例子。我有一个Order对象,它是聚合根。我还有OrderNote对象,它们是订单的子项。当我向Order添加OrderNote然后保存Order时抛出异常,因为CreatedDate / UpdatedDate设置为DateTime.MinValue,这将导致SQL DateTime溢出。由于这些审计列是持久性的一部分而与问题域无关,因此我不希望订单聚合根在添加注释时设置这些属性。审计列/属性只应由持久性框架而不是域知道。我希望能够告诉NHibernate在保存或更新时设置这些属性。有没有办法做到这一点?


9378
2017-07-20 13:53


起源



答案:


拦截器可以做到这一点:

http://www.nhforge.org/doc/nh/en/index.html#manipulatingdata-interceptors (9.10,链接并不总是有效)。

从文档剪切/粘贴:

public class AuditInterceptor : IInterceptor
{
    ...

    public boolean OnSave(object entity,
                          object id,
                          object[] state,
                          string[] propertyNames,
                          IType[] types)
    {
        if ( entity is IAuditable )
        {
            for ( int i=0; i<propertyNames.Length; i++ )
            {
                if ( "CreateTimestamp" == propertyNames[i] )
                {
                    state[i] = DateTime.Now;
                    return true;
                }
            }
        }
        return false;
    }

}

OnFlushDirty()可用于UpdatedDate。

您将希望每个具有CreatedDate / UpdatedDate的实体都实现一个接口,以便拦截器可以检查它是否应该行动(在提供的示例中它是IAuditable)。


编辑

刚刚注意到第11章:拦截器和事件。您可以从EmptyInterceptor继承,如果您只需要覆盖某些方法,这将使事情变得更容易。

我从未使用过活动。


11
2017-07-20 14:46



大。这正是我正在寻找的。我是NHibernate的新手,并没有意识到这个功能。我确实有一个使用受保护属性实现的IAuditable接口,因此域无法看到它们。 - awilinsk


答案:


拦截器可以做到这一点:

http://www.nhforge.org/doc/nh/en/index.html#manipulatingdata-interceptors (9.10,链接并不总是有效)。

从文档剪切/粘贴:

public class AuditInterceptor : IInterceptor
{
    ...

    public boolean OnSave(object entity,
                          object id,
                          object[] state,
                          string[] propertyNames,
                          IType[] types)
    {
        if ( entity is IAuditable )
        {
            for ( int i=0; i<propertyNames.Length; i++ )
            {
                if ( "CreateTimestamp" == propertyNames[i] )
                {
                    state[i] = DateTime.Now;
                    return true;
                }
            }
        }
        return false;
    }

}

OnFlushDirty()可用于UpdatedDate。

您将希望每个具有CreatedDate / UpdatedDate的实体都实现一个接口,以便拦截器可以检查它是否应该行动(在提供的示例中它是IAuditable)。


编辑

刚刚注意到第11章:拦截器和事件。您可以从EmptyInterceptor继承,如果您只需要覆盖某些方法,这将使事情变得更容易。

我从未使用过活动。


11
2017-07-20 14:46



大。这正是我正在寻找的。我是NHibernate的新手,并没有意识到这个功能。我确实有一个使用受保护属性实现的IAuditable接口,因此域无法看到它们。 - awilinsk


您还可以查看NHibernate的版本控制系统,它可以为您提供帮助;)


1
2017-07-20 14:52