tags:

views:

367

answers:

1

Hey,

I have a web service that accepts an Invoice, which contains LineItem children. It then updates the database to either create or update the Invoice using NHibernate.

When an invoice is updated, it is passed to the web service along with all LineItem children it now has. Adds and updates work perfectly. However, if a child LineItem is deleted from a previously persisted Invoice by the Web Service consumer and re-submitted, that LineItem is not actually removed from the database, but rather it's back reference to the parent is set to NULL. I am using (trying to use) cascade="all-delete-orphan" without success.

I suspect that the problem might be due to the stateless nature of the operation (I don't first have the LineItem in Invoice.LineItemList on the web service side and then delete it, but rather just get a list of LineItem's as they now should be). However, NHibernate IS smart enough to null the back-reference column, so I hope there's a straightforward way to get it to delete that row instead.

Here are the mappings (simplified).

Parent object (Invoice):

<property name="InvoiceNumber" />
        <!-- If inverse="true", InvoiceId is NOT set to NULL and the record remains -->
<bag name="LineItemList" table="lineitems" inverse="false"  cascade="all-delete-orphan">
  <key column="InvoiceId"/>
  <one-to-many 
    class="LineItem"/>
</bag>

Child Objects (LineItems):

<many-to-one lazy="false" name="Parent" column="InvoiceID" not-null="false"
             class="Invoice,Company.Business"
             />

<property name="LineItemNumber" />
<property name="SalesAmount"/>

The Web Service persistence code looks like this:

[WebMethod]

public Invoice PutInvoice(Invoice invoice) { // Necessary to rebuild parent references, see Blog

foreach (LineItem item in invoice.LineItems)
{
 item.Parent = invoice;
}

using (PersistenceManager pm = new PersistenceManager())
{
 pm.Save<Invoice>(invoice);
}

return invoice; // Return version potentially modified with DB-assigned ID

}

+1  A: 

You are right this has to to with the detached state of your objects and is a known limitation in admission to performance which NHibernate describes as the not implemented feature of 'persistence of reachability'. However you could of course easily delete all LineItems without valid invoice reference but i also don't like this solution. Usually i use client objects to achieve statelessness which of course results in loading the invoice before manipulating.

zoidbeck
I was considering the strategy of loading the invoice first on the server side, but that's quite an unnecessary performance hit.Currently I lean toward just cleaning up the orphaned records now and then, but as you say, it ain't pretty.
Eric J.