Search code examples
nhibernatenhibernate-mappinghierarchyid

How to Populate a Set Collection of Children from HierarchyId in nHibernate


I have the parent side of the mapping, but am unsure how to properly map the children side.

Parent Mapping

<many-to-one name="Parent" class="NHibernate.Map.OrganizationUnit, CentralDataLayer">
    <formula>(
        SELECT o.`ou_id`
        FROM `global`.`wmtb_orgunit` o
        WHERE o.`ou_hid` = `ou_hid`.GetAncestor(1)
    )</formula>
</many-to-one>

I think the children would map like this. How is possible to populate the parent HierarchyId into the where clause?

Children Mapping

<set name="Children" inverse="true" cascade="all" where="`ou_hid` != :HierarchyId and `ou_hid`.IsDescendantOf(:HierarchyId) = 1">
    <key column="`ou_hid`" />
    <one-to-many class="NHibernate.Map.OrganizationUnit, CentralDataLayer" />
</set>

Solution

  • I believe I've determined the best way to populate the direct descendants of a HierarchyId. In order for this functionality to work, a filter needs to be created on the class and a method of the class will run to query the descendants.

    Further information on setting up HierarchyId support in NHibernate.

    Children Mapping

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CentralDataLayer" namespace="NHibernate.Map" schema="`global`">
    
        <class name="NHibernate.Map.OrganizationUnit, CentralDataLayer" table="`orgunit`">
            ...
    
            <property name="HierarchyId" column="`ou_hid`" type="NHibernate.UserTypes.HierarchyId, CentralDataLayer" not-null="true" />
    
            <filter name="FilterChildren" condition="`ou_hid`.IsDescendantOf(:HierarchyId) = 1 and `ou_hid`.GetLevel() = :HierarchyIdLevel" />
        </class>
    
        <filter-def name="FilterChildren">
            <filter-param name="HierarchyId" type="NHibernate.UserTypes.HierarchyId, CentralDataLayer" />
            <filter-param name="HierarchyIdLevel" type="Int16" />
        </filter-def>
    </hibernate-mapping>
    

    Class Object

    namespace NHibernate.Map
    {
        using Criterion;
        using Microsoft.SqlServer.Types;
        using NHibernate;
        using System.Collections.Generic;
    
        public partial class OrganizationUnit
        {
            #region Fields
    
            private SqlHierarchyId _hierarchyId;
            private ICollection<OrganizationUnit> _children;
    
            #endregion Fields
    
            #region Properties
    
            /// <summary>
            ///     Hierarchy Id
            /// </summary>
            [Description("Get the OrganizationUnit hierarchy id.")]
            public virtual SqlHierarchyId HierarchyId
            {
                get { return _hierarchyId; }
                protected internal set { _hierarchyId = value; }
            }
    
            #endregion Properties
    
            #region Public Methods
    
            /// <summary>
            ///     Get all direct child OrganizationUnits of current OrganizationUnit.
            /// </summary>
            /// <param name="provider">The DataProvider houseing the current Session</param>
            /// <returns></returns>
            public virtual ICollection<OrganizationUnit> GetChildren(ISession session)
            {
                if (_children.IsDefault()) {
                    // Enable Filter
                    session
                        .EnableFilter("FilterChildren")
                        .SetParameter("HierarchyId", HierarchyId)
                        .SetParameter("HierarchyIdLevel", (short)(HierarchyId.GetLevel() + 1));
    
                    // Collect Direct Children
                    _children = session.QueryOver<OrganizationUnit>().List();
    
                    // Disable Filter
                    session.DisableFilter("FilterChildren");
                }
                return _children;
            }
    
            #endregion Public Methods
        }
    }