views:

262

answers:

0

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.