I have two domain objects: Product
and ProductDictionary
, which are both abstract classes and they both have many concrete subclasses. They are connected via many-to-many association. I would like to reuse one join table for all associations between Product
and ProductDictionary
subclasses, because I don't want to polute my DB with unnecessary join tables. Let's say that join table is ProductProductDictionaries
and let's assume that Product
has two subclasses Account
and Card
and ProductDictionary
has also two subclasses GeographicalArea
and ProductDocument
.
My mapping files are like this:
Product:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel" default-lazy="true">
<class name="Product" table="Products">
<cache usage="read-write"/>
<id name="id" column="id" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb"></generator>
</id>
<discriminator column="product_type" type="String"/>
<version name="version" column="row_version" access="field" type="int" unsaved-value="0"/>
<property name="Name" column="name" type="string" length="400" />
<property name="Description" column="description" type="string" length="4001" />
<idbag name="GeographicalAreas" generic="true" table="ProductProductDictionaries" access="field.camelcase-underscore">
<collection-id column="id" type="Guid">
<generator class="guid.comb"></generator>
</collection-id>
<key column="product_id" />
<many-to-many class="GeographicalArea" column="product_dictionary_id" where="dictionary_type='GeographicalArea'" />
</idbag>
<idbag name="ProductDocuments" generic="true" table="ProductProductDictionaries" access="field.camelcase-underscore">
<collection-id column="id" type="Guid">
<generator class="guid.comb"></generator>
</collection-id>
<key column="product_id" />
<many-to-many class="ProductDocument" column="product_dictionary_id" where="dictionary_type='ProductDocument'" />
</idbag>
<subclass name="Account" discriminator-value="Account">
<property name="ValidFrom" column="valid_from" type="string" length="4001" />
</subclass>
<subclass name="Card" discriminator-value="Card">
<property name="Limit" column="limit" type="string" length="4001" />
<property name="Insurance" column="insurance" type="string" length="4001" />
</subclass>
</class>
ProductDictionary:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel" default-lazy="true"><class name="ProductDictionary" table="ProductDictionaries">
<cache usage="read-write"/>
<id name="Id" column="id" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb"></generator>
</id>
<discriminator column="dictionary_type" type="String"/>
<version name="Version" column="row_version" access="field" type="int" unsaved-value="0"/>
<property name="Name" column="name" type="string" length="4001" />
<idbag name="Products" generic="true" table="ProductProductDictionaries" access="field.camelcase-underscore" inverse="true">
<collection-id column="id" type="Guid">
<generator class="guid.comb"></generator>
</collection-id>
<key column="product_dictionary_id" />
<many-to-many class="Product" column="product_id" />
</idbag>
<subclass name="GeographicalArea" discriminator-value="GeographicalArea">
</subclass>
<subclass name="ProductDocument" discriminator-value="ProductDocument">
</subclass>
Notice, that there is 'where' attribute in 'many-to-many' tag in both idbags in Product
mapping. Because of this extra 'where', collections like Product.GeographicalAreas
or Product.ProductDocuments
are properly fetched via the same join table. There is however problem with deletions of elements from this collections. Let's say that you have two objects in GeographicaAreas
and also two objects in ProductDocuments
. When you delete first object from GeographicaAreas
(and commit) NHibernate will perfom deletion using primary key id
from idbag and everything works fine, but if you try to delete last element of GeographicaAreas
, then NHibernate will perfom deletion using foreign key product_id
and therefore delete also all objects from ProductDocuments
, because they both use the same join table. Does anybody know, why NHibernate perform that kind of action? Is this some kind of optimization? Is it possible to switch off this behavior?
I have also noticed that when I use <bag/>
instead of <ibag/>
NHibernate uses foreign key not only when I delete last element from the collection, but in deletions of all elements.