【问题标题】:NHibernate - listener not getting applied to cascaded childNHibernate - 侦听器未应用于级联子级
【发布时间】:2012-07-15 20:06:42
【问题描述】:

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

我有三个监听器:Save、Update、Delete。如果被持久化的对象实现了 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 字段为空,我在数据库中得到一个空值异常。

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

您的帮助将不胜感激!

谢谢大家

【问题讨论】:

    标签: c# nhibernate cascade


    【解决方案1】:

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

    就我而言,以下事件有效:IPreInsertEventListenerIPreUpdateEventListenerIPreDeleteEventListener

    我之前的回答错了!

    正确答案:

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

    希望尽快得到答复。

    但我认为您的问题应该涉及以下侦听器:“merge”、“save-update”、“save”、“update”、“pre-collection-recreate”、“pre-collection-remove”和“pre -collection-update”。

    我之前的回答又错了!

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

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

    *“Merge”、“save-update”、“save”、“update”、“pre-collection-recreate”、“pre-collection-remove”和“pre-collection-update”

    这段代码显示:

    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”。

    【讨论】:

    • 那么你的意思是我正在听的事件不正确?我应该做你的吗?但这会保证 SecSessionLog 子对象也会被传递吗?
    • 那么哪些事件有效?我正在使用 IPreInsertEventListenerIPreUpdateEventListener 都没有被调用。
    • 没关系。我在场上没有空值。看起来验证在事件侦听器之前运行...
    猜你喜欢
    • 2021-04-24
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多