17
votes

I had successfully written a system that contained an order with child order lines, using cascade updates from the order to save the order lines. In the next iteration I want to associate the order lines with a despatch class. This seemed quite straight forward - add a nullable DespatchID column to the order line table as a foriegn key to the Despatch table. However, when I add this to the mapping and save the order object with the despatches not set on the order lines, I get the error "object references an unsaved transient instance - save the transient instance before flushing".

If I remove the association between the order line and the despatch, it saves OK. I can only presume that the error is caused because it is trying to save the despatch, which does not exist.

Here are the mappings (the order lines class is called OrderProductAmount):

  <class name="NHS.WebTeam.PandemicFluDistribution.Order, NHS.WebTeam.PandemicFluDistribution" table="[Order]" lazy="false" optimistic-lock="version" where="Deleted=0" >
    <id name="ID" type="Int32" column="OrderID" unsaved-value="0">
      <generator class="hilo">
        <param name="table">NHibernateHiLo</param>
        <param name="column">NextValue</param>
        <param name="max_lo">100</param>
      </generator>
    </id>

    <version column="version" name="Version"/>
    <property name="Deleted" column="Deleted" />

    <property name="DateEntered"></property>
    <property name="RequiredDeliveryDate"></property>

    <many-to-one name="Practice" column="PracticeID"></many-to-one>

    <set name="OrderProductAmounts" access="field.camelcase-underscore" inverse="true" cascade="all-delete-orphan" lazy="true">
      <key column="OrderID"></key>
      <one-to-many class="NHS.WebTeam.PandemicFluDistribution.OrderProductAmount, PandemicFluDistribution" />
    </set>

  </class>

  <class name="NHS.WebTeam.PandemicFluDistribution.OrderProductAmount, NHS.WebTeam.PandemicFluDistribution" table="OrderProductAmount" lazy="false" optimistic-lock="version" where="Deleted=0" >
    <id name="ID" type="Int32" column="OrderProductAmountID" unsaved-value="0">
      <generator class="hilo">
        <param name="table">NHibernateHiLo</param>
        <param name="column">NextValue</param>
        <param name="max_lo">100</param>
      </generator>
    </id>

    <version column="version" name="Version"/>
    <property name="Deleted" column="Deleted" />

    <many-to-one name="Order" column="OrderID"></many-to-one>
    <many-to-one name="ProductAmount" column="ProductAmountID"></many-to-one>
    <many-to-one name="Despatch" column="DespatchID" cascade="none" not-null="false"></many-to-one>
  </class>

  <class name="NHS.WebTeam.PandemicFluDistribution.Despatch, NHS.WebTeam.PandemicFluDistribution" table="Despatch" lazy="false" optimistic-lock="version" where="Deleted=0" >
    <id name="ID" type="Int32" column="DespatchID" unsaved-value="0">
      <generator class="hilo">
        <param name="table">NHibernateHiLo</param>
        <param name="column">NextValue</param>
        <param name="max_lo">100</param>
      </generator>
    </id>

    <version column="version" name="Version"/>
    <property name="Deleted" column="Deleted" />

    <property name="DateDespatched"></property>
    <property name="RequiredDeliveryDate"></property>

    <many-to-one name="Practice" column="PracticeID"></many-to-one>

    <set name="OrderProductAmounts" access="field.camelcase-underscore" inverse="true" cascade="none" lazy="true">
      <key column="DespatchID"></key>
      <one-to-many class="NHS.WebTeam.PandemicFluDistribution.OrderProductAmount, PandemicFluDistribution" />
    </set>

  </class>

The code to create the order is essentially this:

Dim practice = ... get relevant Practice ...
Dim productAmount = ... get relevant ProductAmount ...
Dim newOrder as Order = new Order(practice)
newOrder.AddProductAmount(new OrderProductAmount(newOrder, productAmount)
OrderDAO.Save(newOrder)

Does anybody have any ideas?

1
I'm quite sure that you're referencing a dispatch class here. Show me the code where the instance is created or loaded and stored ...Stefan Steinegger
I've added an approximation of the code that creates the order to the question. I haven't written the bit that adds the despatch to the order lines yet, so I wouldn't have thought that there would be an association between them yet.Richard Bramley
When you are creating the Order object what value do you assign to the Despatch property? If it's not a NULL, and instead is a Despatch object with its Id = 0, I think NHibernate will throw that exception.El Cheicon
I've debugged the code and when the order is being saved the Despatch on the order line is definitely NULL.Richard Bramley

1 Answers

21
votes

As implied by the comments above (for which a big thanks), there was something that didn't sound right about the Despatch. And, as it turned out, the Despatch was not the problem. Although for some reason it worked before I added it.

I resolved the problem by adding a cascade="all" to the OrderProductAmount link to the Order:

<many-to-one name="Order" column="OrderID" cascade="all"></many-to-one>

The error that was thrown was that the Order was still transient when the OrderProductAmount was being saved. This is very confusing since it is the Order and not the OrderProductAmount that I am saving - the OrderProductAmounts are only saved through a cascade from the Order.

So, if anybody has any ideas why this might be, I'd be interested to know.