NHibernate - 监听器未应用于级联子级

时间:2012-07-15 20:06:42

标签: c# nhibernate cascade

我在Nhibernate和一个非常简单的父子关系中遇到以下问题。

我有三个听众:保存,更新,删除。如果持久化的对象实现IAuditCreate接口,我将分配CreatedDate字段。

我的父映射

<hibernate-mapping assembly="Model" namespace="Model" xmlns="urn:nhibernate-mapping-2.2">
  <class name="SecSession" table="SEC_SESSION" lazy="true" >
    <id name="SecSessionId">
      <column name="SEC_SESSION_ID" sql-type="bigint" not-null="true" />
      <generator class="identity" />
    </id>
    <property name="CreatedDate">
      <column name="CREATED_DATE" sql-type="datetime" not-null="true" />
    </property>
    <bag name="SecSessionLogs" inverse="true" cascade="all-delete-orphan" >
      <key column="SEC_SESSION_ID" />
      <one-to-many class="SecSessionLog" />
    </bag>
  </class>
</hibernate-mapping>

我的孩子映射

<hibernate-mapping assembly="Model" namespace="Model" xmlns="urn:nhibernate-mapping-2.2">
  <class name="SecSessionLog" table="SEC_SESSION_LOG" lazy="true" >
    <id name="SecSessionLogId">
      <column name="SEC_SESSION_LOG_ID" sql-type="bigint" not-null="true" />
      <generator class="identity" />
    </id>
    <many-to-one lazy="false" name="SecSession">
      <column name="SEC_SESSION_ID" sql-type="bigint" not-null="true" />
    </many-to-one>
    <property name="LogMessage" type="StringClob">
      <column name="LOG_MESSAGE" sql-type="nvarchar(max)" not-null="true" />
    </property>
    <property name="CreatedDate">
      <column name="CREATED_DATE" sql-type="datetime" not-null="true" />
    </property>
  </class>
</hibernate-mapping>

所以我创建了一个SecSession对象,然后调用SecSession.AddLog(new SecSessionLog)。

坚持,我做:

using (var dataSession = DataStore.OpenDataSession())
  using (var transaction = dataSession.BeginTransaction())
  {
    var id = (PK)dataSession.Save(secSession);
    transaction.Commit();
    return id;
  }

我没有显式发送SecSessionLog来保存,因为映射说:CASCADE = ALL-DELETE-ORPHAN。

所以这里的问题是没有为子Log对象调用监听器,因此CreatedDate字段为空,我在数据库中得到一个空值异常。

映射中是否缺少配置?在听众中?

非常感谢您的帮助!

全部谢谢

1 个答案:

答案 0 :(得分:2)

我也使用级联到应用程序中。在我的情况下,我需要拦截命令“insert”,“delete”和“update”,以确保在执行的操作范围内只保留特定的实体子集。

就我而言,以下活动有效:IPreInsertEventListenerIPreUpdateEventListenerIPreDeleteEventListener

我之前的回答是错的!

正确答案:

您不能使用'IPreInsertEventListener',那时,更改实体的属性无效。它就是这样发生的,因为NHibernate已经捕获了用于运行SQL命令的数据。我测试了它。

我希望尽快得到答案。

但我认为你的问题应该涉及以下听众:“merge”,“save-update”,“save”,“update”,“pre-collection-recreate”,“pre-collection-remove”和“pre” -collection更新”。

我之前的回答是错误的!

我已经测试并发现使用上面列出的事件*需要大量编码,我无法使其在“SecSession”中使用“merge”,然后插入和更新级联到“SecSessionLogs”。

有一种方法可以在侦听器中修改后切换回NHibernate属性值。

*“合并”,“保存更新”,“保存”,“更新”,“预收集 - 重新创建”,“预收集 - 删除”和“预收集更新”

此代码显示:

public class AuditCreateListener : IPreInsertEventListener, IPreUpdateEventListener
{
    public bool OnPreInsert(PreInsertEvent @event)
    {
        return this.OnEventCommon(
            @event, 
            new Action<object[]>(
                delegate(Object[] newState) 
                {
                    newState.CopyTo(@event.State, 0);
                }));
    }

    public bool OnPreUpdate(PreUpdateEvent @event)
    {
        return this.OnEventCommon(
            @event,
            new Action<object[]>(
                delegate(Object[] newState)
                {
                    newState.CopyTo(@event.State, 0);
                }));
    }

    private bool OnEventCommon(AbstractPreDatabaseOperationEvent @event, Action<object[]> setStateCallback)
    {
        IAuditCreate auditCreate = @event.Entity as IAuditCreate;
        if (auditCreate != null && auditCreate.CreatedDate == null)
        {
            auditCreate.CreatedDate = DateTime.Now;

            if (setStateCallback != null)
            {
                Object[] newState = @event.Persister.GetPropertyValues(auditCreate, EntityMode.Poco);
                setStateCallback(newState);
            }
        }

        return false;
    }
}

很快我会发布完整的消息来源。

再次编辑:

概念证明:

  • AuditCreateListenerBrokenTet:测试事件:“save”,“save-update”,“update”,“merge”,“flush-entity”,“pre-collection-recreate”,“pre-collection -remove“和”pre-collection-update“。
  • AuditCreateListenerTet:对事件进行测试:“预更新”和“预插入”。

表格内容:

SEC_SESSION:

#|SEC_SESSION_ID|CREATED_DATE    
-+--------------+----------------
1|1             |2012-07-10 16:53
2|2             |2012-07-11 16:53
3|3             |2012-07-12 16:53
4|4             |2012-07-13 16:53

SEC_SESSION_LOG:

#|SEC_SESSION_LOG_ID|LOG_MESSAGE  |CREATED_DATE    |SEC_SESSION_ID
-+------------------+-------------+----------------+--------------
1|1                 |LOG_MESSAGE_1|2012-07-10 16:53|1             
2|2                 |LOG_MESSAGE_2|2012-07-11 16:53|2             
3|3                 |LOG_MESSAGE_3|2012-07-12 16:53|3             
4|4                 |LOG_MESSAGE_4|2012-07-13 16:53|4             

我正在使用:

  • NHibernate 3.2.0
  • System.Data.SQLite 1.0.80.0

完整的来源是:Q11495204.7z

注意:

  • 在打开解决方案(“。\ Src \ SofPOC.2010.sln”)之前,运行“。\ Dependencies \ setup.bat”以加载依赖项。
  • 有关依赖项的说明,请参阅“。\ readme.txt”和“。\ dependencies \ readme.txt”。