NHibernate Gotchas - Orphans and one-to-one
I'd previously posted about NHibernate Gotchas but we just came accross a big one, cascade options on one-to-one.
Essentially we'd used the cascade option "all-delete-orphan" on a
Unfortunately the cascade option was totally ignored and indeed after quite a bit of effort we found that the docs do indicate its not supported an its a known issue.
Workarounds, not sure. Deleting the one-to-one from the ISession directly is not an option for us in our POCO domain so we may need to look at other mappings.
Worth knowing anyway!
Did you ever find a reasonable solution?
ReplyDeleteDid you ever find a reasonable solution?
ReplyDeleteAfraid not, none of the solutions we found were particularly good...
ReplyDeleteWhat did you ultimately do to as a workaround? The only solution I can think of is to either first delete the child then save the entity or sync the child Id's. Ugh.
ReplyDeleteAfter spinning on this for a while, I thought I would share my workaround:
ReplyDeleteContext:
* Registration has 1 Payment.
* A Payment could be a CreditCardPayment, CashPayment, MoneyOrderPayment or CheckPayment.
* A Payment has 1 Payee
* A Payee could be an IndividualPayee, OrganizationPayee, RegistrantPayee
So in the Registration mapping I have:
<many-to-one class="Payment" column="[PaymentId]" name="payment" access="field" cascade="all-delete-orphan" lazy="false" fetch="join" />
in the Payment mapping I have:
<one-to-one constrained="true" name="registration" access="field" property-ref="payment" />
<many-to-one class="Payee" column="[PayeeId]" name="payee" access="field" cascade="all-delete-orphan" fetch="join" lazy="false" />
Ideally, I wanted to map Payment and Payee as components of a Registration, but as you know, there is no component inheritance in NHibernate.
My API works like this:
Registration r = new Registration());
r.Payment = new CashPayment();
In order to handle the orphans, I bascially had to create a query to get all of the existing "orphans" and then delete those.
//delete all payee orphans
Repository<Payee>.DeleteAll(new Query<Payee>(@"from Payee payee
where payee not in(select payment.payee from Payment payment where payment.payee is not null)"));
//delete all payment orphans
Repository<Payment>.DeleteAll(new Query<Payment>(@"from Payment p
where p not in(select r.payment from Registration r where r.payment is not null)"));
Additionally, I had to first "save" my registration in its own transaction. Then run the "delete orphans" code its own transaction.
To bad the "all-delete-orphan" doesn't work for many-to-one or one-to-one mappings!
Not very nice but you could use a simply if-statement to simply not execute the nhibernate delete statement if the object is just an in-memory object instead of a persistent one? Yes that is kind of a hack, but better than having to alter the mappings.
ReplyDelete