I’m using nHibernate to map an object very similar to .NET’s System.Web.SiteMapNode. In order to keep my object similar to this .NET object I would like to have it contain a ParentNode, PreviousSibling, NextSibling, and ChildNodes complex properties.
The table looks somewhat like this and is open to be changed:
- ID (int)
- Title (string)
- Description (string)
- Key (string)
- ParentNodeId (int)
- OrdinalPosition (int)
- ReadOnly (bool)
- Url (string)
I may have some other properties that are not needed to mimic the .NET SiteMapNode object (like an isExternal bool), but I think those are inconsequential to this question.
My current mapping looks like this:
<hibernate-mapping xmlns='urn:nhibernate-mapping-2.2' namespace='AthletesCafe.Core.Domain.System.SiteMap' assembly='AthletesCafe.Core'> <class name='SiteMapNode' table='SiteMapNode' lazy='true' > <id name='ID' type='Int32' unsaved-value='0'> <column name='ID' not-null='true' unique='true' index='PK_SiteMapNode'/> <generator class='identity' /> </id> <property name='Title' column='Title' type='String' length='255' not-null='true' /> <property name='Description' column='Description' type='String' not-null='false' /> <property name='Url' column='Description' type='String' not-null='true' /> <property name='SiteMapKey' column='SiteMapKey' type='String' not-null='true' length='255' /> <property name='OrdinalPosition' column='OrdinalPosition' type='Int32' not-null='true' /> <property name='ReadOnly' column='ReadOnly' not-null='true' type='System.Boolean' /> <property name='IsExternal' column='IsExternal' not-null='true' type='System.Boolean' /> <many-to-one name='ParentNode' column='ParentNodeId' class='AthletesCafe.Core.Domain.System.SiteMap.SiteMapNode, AthletesCafe.Core' access='field.pascalcase-underscore' not-null='false' /> <many-to-one name='PreviousNode' column='ParentNodeId' class='EatMyTrainer.Core.Domain.SiteMap.SiteMapNode, EatMyTrainer.Core' not-null='false' /></hibernate-mapping>
The ParentNode mapping is easy as it should be just a simple many-to-one mapping. This is the code I have for it (untested, but I believe it to be correct):
<many-to-one name='ParentNode' column='ParentNodeId' class='AthletesCafe.Core.Domain.System.SiteMap.SiteMapNode, AthletesCafe.Core' access='field.pascalcase-underscore' not-null='false' />
The mapping for the child nodes should just be a simple bag which will bring back all SiteMapNode objects that have the ParentNodeId equal to the current ID. I haven’t written this bag yet, but I believe it to be not such a big deal.
The issue that I cannot seem to resolve is how to do the Next/Previous Sibling properties. This objects can be derived from the following formula for each node:
- PreviousSibling: Has the same ParentNode (ParentNodeId) as the current object and its OrdinalPosition should be one less than the current object’s OrdinalPosition.
- NextSibling: Has the same ParentNode (ParentNodeId) as the current object and its OrdinalPosition should be one more than the current object’s OrdinalPosition.
I think this is achievable through the formual attribute on a many-to-one mapping. Is this possible? I haven’t found a good example of how this works.
I don’t think what you’re asking for is strictly possible (although I would be very interested to see the solution if it is). There would be a relatively simple workaround, but NHibernate does not support bidirectional one-to-many mappings with indexed collections on the many end.
The only thing that comes to mind is a bit ugly: have the parent object keep its own index map (keyed off the OrdinalPosition) to each child object. On the child do something like: