Hi All
I have a very deep class hierarchy in my domain model and want to use discriminator tag to support inheritance.
Initially i mapped my classes using join-subclass, however the tables involved have hundreds of thousands of records and it is turning out to be a performance bottleneck. So in essence i want to flatten my table structure without touching the domain and that's why we moved on to discriminator tag.
My hibernate mappings looks like(have deleted the extra column for sake of simplicity)
Code:
<!--Hibernate mapping for Transaction-->
<hibernate-mapping>
<class name="Transaction"
table="transaction" abstract="true">
..........
<discriminator column="transaction_type" type="string"/>
.........
</class>
</hibernate-mapping>
<!--Hibernate mapping for CashBasedTrsansaction having all the subsequent child classes-->
<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 for Invoice-->
<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.
Problem : Hibernate is creating a column "invoice_id" in transaction table(this is wrong) as well as in billing_transaction(this is correct). On further debugging i found some interesting results and need some feedback/advice.
- Hibernate creates a column invoice_id in billing_transaction which is what i want. The following code is responsible for it
Code:
<join table="billing_transaction">
<key column="id" />
<many-to-one name="invoice" column="invoice_id" cascade="all" access="field"
lazy="false" index="billing_transaction_n1">
</many-to-one>
</join>
- Hibernate also creates invoice_id in Transaction which is not what i want. The following code is responsible for it...
Code:
<bag name="billingTransactions" access="field" cascade="all" inverse="true" table="billing_transaction">
<key column="invoice_id" />
<one-to-many class="BillingTransaction" />
</bag>
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
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???