`

What happened behind "AllDeleteOrphan" mapping in NHibernate

 
阅读更多

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).

 

http://blogs.microsoft.co.il/blogs/arnona/archive/2011/07/12/understanding-one-to-many-relationships-in-nhibernate.aspx

Cascade operations

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.

all-delete-orphan

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

Allow nulls?

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:

  1. It persists the parent entity by executing an INSERT statement
  2. If cascade is set to save-update , all , or all-delete-orphan , NHibernate persists each of the child elements by executing an INSERT statement for each of the children. However, because the relationship is not part of the child entity (as it’s defined as a bag element on the parent), the column that defines the key of the bag doesn’t participate in the INSERT and remains NULL . If we use inverse=true, then we can set the child reference to parent not nullable.
  3. It updates the key column of the relationship in the child table with the ID of the parent. (In other words, it associates the children with the parent)

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.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics