views:

63

answers:

2

I have two entities like so (distilled to only what's relevant):

public class Person {
    public virtual Address Address
}

public class Address {
}

Person has a many-to-one relationship with Address, or in object terms, a Person references an Address, and this link is uni-directional (Address does not have a reference back to Person).

Now, if I use this code:

// save a new person with a new address
var person = new Person();
person.Address = new Address();
person.Save();

// change the person's address and save it again
person.Address = new Address();
person.Save();

The first part does what it's supposed to, it creates a new Person and a new Address in the database.

However, the second part will update the existing Person and create a new Address, but it doesn't delete the now-orphaned first address. What do I have to do in order to get NHibernate to recognize that I'm changing the reference to a new entity and automatically 'garbage collect' the orphaned entity? Or do I have to do this manually?

Possible Solution

Although I don't have conclusive evidence that this indeed what's going on, I think the reason for this problem is because of the object-relational impedance mismatch. In programming, we know that objects hold references to other objects, and once those references are lost, garbage collection will come and delete those 'orphaned' objects that no longer have any references pointing to them. In the example I provided, Person has a reference to Address, and once the reference to Address is lost, it will get garbage collected, assuming no other Persons have a reference to it as well.

On the database side, there is no concept of garbage collection. To the database, there is only one-to-many or many-to-many relationships, or in other words, a parent with a collection of children. Going back to Person and Address, we see that this is a one-to-many relationship from Address to Person (each person can only have one address, but an address can belong to many people, such as a household of people that share a common address). The database considers the Address the parent and the Person as a collection of children. Thus, it makes sense that by deleting a Person, the Address should not be deleted as well (put another way, if you have a bookshelf with a collection of books, deleting a book should not delete the bookshelf).

So how do we fix this? We'll have to delete any parents where their child collections are empty. In this case, an Address with an empty collection of Persons should be deleted. This is a business rule, as nothing states that an Address cannot exist by itself, but in the application I'm developing, an Address by itself means nothing if it's not attached to a person, and thus should be eliminated. However, it's entirely possible for the address to remain in an orphaned state until some other Person comes along and references it.

+1  A: 

set cascade="all-delete-orphan" on the relationship

Isaac Cambron
I've already tried that. Although it works for deleting the parent entity (in this case, the `Person` object), it doesn't work if you change the child to a new one. The old one will remain in an orphaned state.
Daniel T.
+1  A: 

There's no reasonable way to do this in NHibernate, even if you map the relationship from the one (Address) side. It's equivalent to asking that an object be automatically deleted when one of its child collections is empty. I don't follow your thinking in your possible solution, but you're correct that this is a business rule.

There are, of course, "bad" ways to accomplish this. If there were a foreign key constraint in the database, you could delete an Address when you change a reference and swallow the exception. If the delete succeeds then it was an orphan, if not then there are still Persons referencing it.

Address is usually on the many side of a relationship, i.e. Person can have multiple addresses. This is, imo, a much better approach. You do end up with duplicate addresses in the Address table but this as repeating data not duplicate data.

Jamie Ide
What's the difference between repeating data and duplicate data?
Daniel T.