What happened behind "AllDeleteOrphan" mapping in NHibernate?
Suppose we have the following mapping for Person and FamilyMember. We expect FamilyMember to be removed from db when we remove it from the person.
[HasMany(typeof(FamilyMember), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true, Fetch = FetchEnum.Select)] public virtual IList<FamilyMember> FamilyMembers { get; set; }
Clear the FamilyMember.
using (var t = new TransactionScope(TransactionMode.Inherits)) { Person p1= GetPerson (1); p1.FamilyMembers.Clear(); }
This is the sql triggered in sql server.
UPDATE persons SET version = @p0, Notes = @p1, primary_email = @p2, secondary_email = @p3,... UPDATE family_members SET person_id = null WHERE person_id = @p0 DELETE FROM family_members WHERE Id = @p0
Noteably, it first set the person_id of family_members to null. So, we have to delcare person_id of family_members to allow nullable. Surely, this will lose the constraint that a family_member must belong to an person.
If we really need to keep the constraint in the db level, we can not use "AllDeleteOrphan" anymore. We may resort to other methods to delete the orphane family_memeber manually, like XXXRepository.remove(familyMember).
In parent-child relationships, when you save, update or delete the parent, usually you want the children to be saved, updated or deleted as well. Note that for components, this happens automatically , but often you want this to be the case even if the children are entities.
Notice that by default, if you remove a child element from its parent, NHibernate can’t determine whether you intend to delete the child element, or only break the association, leaving the child entity without a parent. (Recall the definition of an Entity: it’s has a meaning by its own). Of course that you can call ISession.Delete(child) whenever you remove a child from its parent, but that would be very cumbersome, so NHibernate allows us to specify that we want to delete the children that were removed from their parent (that’s why they called Orphans ), by specifying cascade=”all-delete-orphan” on the <bag …> element
Given a parent/child relationships, if you create a new parent entity with one or more children, and then try to save this parent entity (by calling ISession.SaveOrUpdate for example) NHibernate works as follows:
Beside the fact that a redundant round-trip to the database is required in this case, it also requires that the key column would allow nulls, otherwise the 2nd insert will fail!
In foreign-key and bi-directional relationships this problem does not exist because the key column is part of the child entity.