Hi All
Short Summary of Problem
Hibernate is assuming that whenever someone is using subclass all the columns should be created 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???
Details
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)
Transaction mapping
<class name="Transaction" table="transaction" abstract="true">
...
<discriminator column="transaction_type" type="string"/>
</class>
CashBasedTrsansaction 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><!--End Of AnotherChildOfBillingTransaction-->
</subclass><!--End Of BillingTransaction-->
</subclass><!--End Of CashBasedTransaction-->
Invoice 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>
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.
Hibernate also creates another column with same name i.e. invoice_id in Transaction table which is not what i want.
Now this is frustrating. Even though i have mentioned the table name(Billing_Transaction) in invoice.hbm and have set inverse="true" yet hibernate goes ahead and create a column invoice_id in transaction table even though there is already one in Billing_Transaction. 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???