2
votes

I have an entity "Group" with an assigned ID which is added to an aggregate in order to persist it. This causes an issue because NHibernate can't tell if it is new or existing. To remedy this issue, I changed the mapping to make the Group entity use optimistic locking on a sql timestamp version column. This caused a new issue. Group has a bag of sub objects. So when NHibernate flushes a new group to the database, it first creates the Group record in the Groups table, then inserts each of the sub objects, then does an update of the Group records to update the timestamp value. However, the sql that is generated to complete the update is invalid when the mapping is both dynamic-update="true" and optimistic-lock="version".

Here is the mapping:

<class xmlns="urn:nhibernate-mapping-2.2" dynamic-update="true" mutable="true" optimistic-lock="version" name="Group" table="Groups">
    <id name="GroupNumber" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="GroupNumber" length="5" />
      <generator class="assigned" />
    </id>
    <version generated="always" name="Timestamp" type="BinaryBlob" unsaved-value="null">
      <column name="TS" not-null="false" sql-type="timestamp" />
    </version>
    <property name="UID" update="false" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="GroupUID" unique="true" />
    </property>
    <property name="Description" type="AnsiString">
      <column name="GroupDescription" length="25" not-null="true" />
    </property>
    <bag access="field.camelcase-underscore" cascade="all" inverse="true" lazy="true" name="Assignments" mutable="true" order-by="GroupAssignAssignment">
      <key foreign-key="fk_Group_Assignments">
        <column name="GroupNumber" />
      </key>
      <one-to-many class="Assignment" />
    </bag>
    <many-to-one class="Aggregate" name="Aggregate">
      <column name="GroupParentID" not-null="true" />
    </many-to-one>
  </class>
</hibernate-mapping> 

When the mapping includes both the dynamic update and the optimistic lock, the sql generated is:

UPDATE groups SET WHERE GroupNumber = 11111 AND TS=0x00000007877

This is obviously invalid as there are no SET statements. If I remove the dynamic update part, everything gets updated during this update statement instead. This makes the statement valid, but rather unnecessary.

Has anyone seen this issue before? Am I missing something?

Thanks, Steve

2
can you create a stand-alone testcase? - Mauricio Scheffer

2 Answers

1
votes

I had exactly the same issue, and it took me an age to stumble around the documentation before I finally got it to work. You need to set the optimistic-lock attribute on your bag element to false. This will stop NH from marking the parent for update when no updatable properties have been changed. I hope this works for you.

0
votes

Try setting the unsaved-value attribute in the id element; this should allow NHibernate to distinguish between new and existing records and sidestep the timestamp problem.

<id name="GroupNumber" unsaved-value="" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

The documentation leads me to believe that this should default to empty string but it's worth a try.