views:

9

answers:

0

Hi All

Short Summary : I am using DDD approach to design my domain. This resulted in a very deep object hierarchy in my domain. My ORM tool is hibernate. As we all know that hibernate provide various means of modeling inheritance. Initially i used table per subclass hierarchy to realize this complex domain and very soon i ran into performance issues. So i decided to flatten out my table structure by using hibernate's table per class using discriminator strategy.

However the catch here is that i don't want to flatten out the whole hierarchy into just one table. In my database i still want to maintain hierarchy at some level. Now the question is how to do it??? It seems whenever you use tag in hibernate, it assumes there can be only one table in the database. In short no matter where you start from hibernate will reach the aggregate root of your class hierarchy and create a table belonging to it. Thereafter all the properties of child class will be added to the same table.

Now this leaves me with no option but to create one big flat table sufficing all the properties of my child classes. This is a no-no for me. Can anyone please suggest an alternative???


Here is my code(for those who are interested in details)

My hibernate mappings looks like(have deleted the extra column for sake of simplicity)

<hibernate-mapping>
   <class name="Transaction"
      table="transaction" abstract="true">
        <discriminator column="transaction_type" type="string"/>
   </class>
</hibernate-mapping>
<hibernate-mapping>
<subclass name="CashBasedTransaction"
          extends="Transaction" discriminator-value="CASH">
     <join table="cash_based_transaction">
       <key column="id" />
     </join>

     <subclass discriminator-value="BILLING"
      name="BillingTransaction">
      <join table="billing_transaction">
         <key column="id" />
         <many-to-one name="invoice" column="invoice_id" cascade="all" access="field"
            lazy="false">
         </many-to-one>
      </join>

      <subclass name="ChildBillingTransaction"
         discriminator-value="UPT">
         <join table="billing_transaction">
            <key column="id" />
            ...............
         </join>
      </subclass>
      <subclass abstract="true"
         name="AnotherChildOfBillingTransaction"
         discriminator-value="LPT">

         <subclass
            name="SuperChildOfBillingTransaction"
            discriminator-value="OCLPT">
            <join table="billing_transaction">
               <key column="id" />
               ...........
            </join>
         </subclass>
         <subclass
            name="AnoherSuperChildOfBillingTransaction"
            discriminator-value="SLPT">
            <join table="billing_transaction">
               <key column="id" />
               ..........
            </join>
         </subclass>
      </subclass>
   </subclass>
</hibernate-mapping>
<hibernate-mapping>

   <class name="Invoice" table="invoice">
      .......

      <bag name="billingTransactions"  access="field" cascade="all" inverse="true" table="billing_transaction">
         <key column="invoice_id" />
         <one-to-many class="BillingTransaction" />
      </bag>

      .......     

   </class>
</hibernate-mapping>

What i want to achieve : I want to flatten out table structure after billing_transaction. In other words i want to have only three tables in the database

  • transaction
  • cash_based_transaction
  • billing_transaction(this table should hold all the columns after flattening out all the subclasses)

P.S : Please note that i want to flatten out table structure not from the aggregate root(read transaction) but somewhere down the line in my class hierarchy, billing_transaction in this case.

Now this is frustrating. Even though i have mentioned the table name and have set inverse="true" yet hibernate goes ahead and create a column invoice_id in transaction table. I was expecting that since i am giving it the table name hibernate should take that name and check if billing_transaction has invoice_id or not... Instead hibernate is doing exactly opposite. It is completely ignoring the table name that i have provided and reaching out to the most super class i.e. Transaction. There it creates invoice_id column when it finds out that no such column exists. As a result i have two invoice_id column sitting in my tables. One in billing_transaction where i want it to be and another in transaction table where i don't want it to be.

I have found out the code which is causing it. In org.hibernate.mapping.Subclass table is identified using the below given code

public Property getIdentifierProperty() {
      return getSuperclass().getIdentifierProperty();
   }

In other words hibernate is assuming that whenever someone is using subclass all the columns should be create in the top root of the class hierarchy irrespective of what table name has been provided. Can someone please explain the reasoning behind it and if there is way to bypass this code and somehow avoid invoice_id getting created in transaction table???