1

我对 Nhibernate 和一个非常简单的父子关系有以下问题。

我有三个听众:保存、更新、删除。如果被持久化的对象实现 IAudiCreate 接口,我分配 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 字段为空,我在数据库中得到一个空值异常。

映射中是否缺少要配置的内容?在听众中?

您的帮助将不胜感激!

谢谢大家

4

1 回答 1

2

我还使用级联到应用程序。在我的情况下,我需要拦截“插入”、“删除”和“更新”命令,以确保在执行的操作范围内仅保留特定的实体子集。

就我而言,以下事件有效:IPreInsertEventListener, IPreUpdateEventListener, IPreDeleteEventListener.

我之前的回答是错误的!

正确答案:

不能使用'IPreInsertEventListener',此时,改变实体的属性是没有效果的。之所以会这样,是因为 NHibernate 已经捕获了将用于运行 SQL 命令的数据。我已经测试过了。

我希望很快有答案。

但我认为您的问题应该涉及以下听众:“合并”、“保存更新”、“保存”、“更新”、“预收集-重新创建”、“预收集-删除”和“预收集-更新”。

我之前的回答又错了!

我已经测试并看到使用上面列出的事件*需要大量编码,我无法使其与“SecSession”中的“合并”一起工作,然后插入和更新级联到“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” -更新”。
  • 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”。
于 2012-07-18T06:39:33.703 回答