0
votes

We have an object in our model, call it class X. There are several other classes in our model that have an instance of class X as a property, call them A, B, C, etc. This is essentially a one-to-one mapping, since each X can only belong to one parent class. To map this relationship on the database side, we are currently using a foreign key to the X table in tables A, B, and C. For the NHibernate mappings, we are currently using, in the mappings for the A, B, and C classes:

ManyToOne(a => a.X, m => m.Cascade(Cascade.All));

This mostly works for saving, retrieving, and updating our class Xs - we've had a lot of problems getting NHibernate OneToOne mappings to work right. The problem is that, when you take your persistent class A and replace its X with a new instance of X and then save that A instance, then the new X instance gets written to the database and the foreign key in the A column gets updated, but the old X does not get deleted, so we now have an orphan X.

We would like those orphaned Xes to be automatically deleted. We would like NHibernate to do it, because X is a complex class with many relationships of its own to other tables that we have cascades set up to handle properly - I have a SQL script set up to delete orphan Xes properly, and it's about 50 lines long.

We are trying to avoid solutions that involve putting a reference in class X to its parent item, since there are a total of 5 classes that it can belong to, and situations such as class A has one X, class B has 2 Xes in named properties, etc.

Things I've tried so far:

Adding DeleteOrphans to the ManyToOne mapping - doesn't work

OneToOne mapping - really wants the key to be in the other table, and doesn't seem to support cascade deletes anyways.

Also considered:

NHibernate doesn't seem to have any support for setting up some kind of even to trigger when things like updates or deletes happen

Apparantly, only the OneToMany and ManyToMany mappings support DeleteOrphans, so, I could make the actual property use some kind of list or set, and use getters and setters to make it look like a normal property to the rest of the model. Sounds very hacky, and it might require having a reference in X to the other classes.

Database trigger - I haven't really checked if SQL Server triggers can be used in this way yet, but it sounds like a very awkward solution.

Does anybody have any ideas for how to make this work?

1

1 Answers

0
votes

The solution that we ended up going with here is to never allow a new instance of X to be assigned to any of the classes that hold it. Instead, we have added code to the setters so that, whenever you try to assign a new instance of X, it will actually clear the contents of the existing X and replace them all with the contents of the new X. Since all of the objects contained in X are collections, NHibernate cascade deletes work properly in deleting the old child items of X and replacing them with the new ones. It's a bit of an ugly solution, but it's the least ugly thing we've been able to come up with that works.