NHibernate's <any> association is cool
I need to preface the cool part with also mentioning that
<any> is a part of an evil plot to overtake the world, so don’t use it if
you don’t know what you are doing. If you do, however, it is one hell
of a feature to have.
Currently I’m using it for a set of rules, which can be
applied to several objects, which does not have a common ancestor. This is
usually a problem, since I have no way to map those objects to the database
and back.
It turned out that NHibernate has support for <any>
and <many-to-any> tags which gives you this functionality. Let us
consider the following simple class diagram:
In this case, we have a Rule, which can be applied to an
IValidable instance. How do I persist this to the database? And more
importantly, get it out again cleanly?
Let us take a look at the database diagram:
Second, we will look at the mapping:
<class name='NHibernate.Any.Rule,
NHibernate.Any' table='`Rule`'> <id name='Id'> <generator class='identity'/> </id> <any name='AppliesTo' meta-type='System.String' id-type='System.Int32'> <meta-value class='NHibernate.Any.Account,
NHibernate.Any' value='ACC'/> <meta-value class='NHibernate.Any.Customer,
NHibernate.Any' value='CUST'/> <column name='AppliesToType'/> <column name='AppliesToId'/> </any> </class> |
A couple of points before we continue:
·
The meta-type attribute is not
required in the schema, but omitting it causes some strange results. Always
specify it.
·
The <any> tag has the last
two elements as <column>. There is a very specific meaning to the
ordering of those <column> elements (and it is nearly the only place in
NHibernate where element ordering has a meaning). The first <column>
element specify the column that holds the type of the association, and the
second <column> holds the id of the object that this association points
to.
·
Each <meta-value> element
maps between a class and a value (which is what NHibernate will search on the
Type column).
In this case, both Customer and Account implements
IValidable, and a Rule can be applied to either of them (in this simple
example, it doesn’t really makes sense, but I have a system where IValidable is
a fully fledged interface that exposed enough information to be able to use
just its info to run a significant number of rules).
Now I can just set the AppliesTo attribute to the
appropriate type, and NHibernate will take care of everything for me. This
takes care of quite a bit of complexity, and simplifies my life quite a bit.
Building on this behavior, it is possible to have a very
rich model, and still enjoy the benefits of NHibernate’s capabilities.
Comments
Comment preview