These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: Hibernate inheritance fails to support extension components
PostPosted: Fri Jul 29, 2005 12:20 am 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
Hibernate version: 3.05

The following outlines a common development pattern that I think Hibernate could better support. So far I've hit brick walls attempting to make it work without resorting to compromising workarounds.

This is NOT intended to be any form of Hibernate bashing. In many respects Hibernate 3.0 is a perfect match for the framework I'm developing. I just think that the current inheritance features need some further refinement. If you disagree ... I'm all ears!

Persistence Requirements of an Extensible Component Framework:

* Framework API library employs Hibernate for object persistence.
- Core framework employs persistent POJO classes + Hibernate XML mapping files.
- Framework API auto creates database schema on startup using Hibernate DDL generation.
- Deployed as a single core framework JAR + extension JARs + deployment config file.

* Support for extension components (JARs) that contain persistent classes derived from abstract classes defined in the framework.
- An indefinite number of derived persistent extension classes (potentially hundreds) may be loaded
into a service at any given time.

- Each extension component defines its own Hibernate mappings (Mappings.hbm.xml).
Hibernate generates DB tables for component persisted classes on framework startup.
Deployment configuration file defines the set of components to load at startup.
Infrequent dynamic loading of components after startup is also supported (Rebuilds SessionFactory).

- By convention, each extension JARs contains a single package hierarchy based on a common root package name.
To avoid database table name collisions between components, persistent classes within a given
package hierarchy are mapped to tables with a common prefix using Hibernate DefaultNamingStrategy feature.
Deployment configuration file (external to the extension JARs) defines the unique table prefix for DB tables
used by each extension component.

- Standard HibernateUtil.java class replaced with a more "component friendly" alternative.

Hibernate Headaches:

Hibernate *nearly* supports this pattern but its inheritance mapping features appear to break in a few strategic places.

A key problem is that Hibernate appears to have been designed with the assumption that a base class will have a small and limited number of derived classes (low fanout). Unfortunately this is not the case in the framework pattern where an indefinitely large number of dynamically loaded derived classes may exist (high fanout). In this scenario, outer joins and unions over derived class tables become infeasible. At best they are slow (lots of joins or unions). At worst, they can fail to execute
because the database join (or union) count limits are exceeded within an SQL query.

The other main problem is that the <joined-subclass> tag does not offer some of the important features available in <join>. Putting <join> inside <subclass> creates a disjointed (no pun intended) coupling that does not cleanly support mixed inheritance mapping within a class hierarchy with more than 2 levels.

Inheritance mapping options:

What the framework pattern needs is support for "Table per subclass hierarchy" with a single table used for the base class and lazy loading of the subclass fields. It also requires table name generation for derived classes that uses .

Here's what Hibernate appears to offer:

Option 1: Table per class hierarchy

- Always employs outer joins so high derived class fanout is an issue. (?? Correct ??)
Slow at best, SQL breaks at worst.

- Won't support lazy loading of the derived class fields.
The core framework classes are normally only interested in base class fields but they are forced to load data from potentially 100's of derived component classes across 100's of tables.
*** Note: Adding the fetch="select" attribute to <joined-subclass> would fix the problem! ***

- No way to safely avoid name collisions between field names in derived classes since they are inside components that may be developed by different component authors.

Option 2: Table per subclass
- Employs outer joins to determine the derived class type.
Unacceptable performance cost or SQL failure with potentially 100's of derived classes that will map to 100's of tables.

- <joined-subclass> does not support fetch="select" that is required for lazy loading of the derived class.

Option 3: Table per subclass, using a discriminator and <join fetch="select">

Quote:
<class name="Base">
<id name="id" type="long">
<generator class="native"/>
</id>

<discriminator column="ComponentType" type="string"/>

<subclass name="DerivedA">
<join table="Component1_DerivedA" fetch="select">
...
</join>
</subclass>
</class>


- fetch="select" provides the needed lazy loading of derived class fields

- v3.05 does not generate DDL to create the joined table. (??Bug??)

- No support for table per subclass.
Instead you must use an other <join> inside each class derived from the component subclasses.

- Forced to specify the table name prefix (like "Component1_DerviedA" above) rather than have it be generated based on the class name and DefaultNamingStrategy interface.
- The table prefix must be specified at deployment time to avert collisions of table name prefixes.
Hence the table name cannot be coded into the mapping XML file.
- Invokes DefaultNamingStrategy.(String tableName) rather than using DefaultNamingStrategy.classToTableName(String classPath) that is needed by the framework pattern to generate the unique component specific table name prefixes.

- Component class *hierarchy* is forced to use a new <join> table for each inheritance level rather than use a single table for the component class hierarchy.

Option 4: Table per concrete class using <union-subclass>

- Same high fanout problems - You end up doing union across 100's of tables.

Option 5: Table per concrete class, using implicit polymorphism

- Same high fanout problems - You end up doing union across 100's of tables when the framework needs to query over the base class.

Workaround Hack

A workaround is a to avoid having a base class by instead using using an association relationship (rather than inheritance) between base class and derived component classes. A discriminator field is used but its is mamaged by the framework base class (rather than Hibernate) to select the "derived" class . If override methods are required, then they can be declared in an interface with matching delagate methods in the orginal base class.

This is clearly a compromise that results in the framework developer doing some of the mapping work that Hibernate is supposed to support.
[/list]


Top
 Profile  
 
 Post subject: Hibernate inheritance fails to support extension components
PostPosted: Mon Aug 01, 2005 1:04 am 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
The workaround also requires the framework developer to perform cacade deletes across the association.


Top
 Profile  
 
 Post subject: Framework components and table name generation
PostPosted: Tue Sep 20, 2005 8:13 pm 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
Another limitation of using <join> inside <subclass> is that it forces you to specifiy the table names used in the joined subclass rather than simply defaulting to the subclass name.

The problem here is that when you're dealing with plugin components for a framework you need to be able to specify *at deployment time* a unique prefix for the tables used by a each extension component rather then wiring this into the component's Mapping.hbm.xml file. This ensures that table naming conflicts can be resolved by a deployment configuration document when the framework component are deployed. The deployment config can map a package name to a table prefix. This config is used by a class derived from DefaultNamingStrategy. However, a problem arrises with use of <join> in that it invokes DefaultNamingStrategy.tableName() rather than DefaultNamingStrategy.classToTableName() so the package -> table prefix mapping cannot be used.

So once again use of <subclass> and <join> appears to be an incomplete "bandaid" solution. What should be supported is use of <join> attributes at the <joined-subclass> level. Current use of <subclass> and <join> limits us to a single subclass tier with poor support for generating table names.

****
I think that Hibernate should be able to create a base class hierarchy that maps to a single table and then be able to create subclass hierarchies that each map to a single table with the option of lazy loading between these tables in order to avoid the overheads and risks of and indefinate number of joins or unions when high fan out occurs (such as in extensible component frameworks). Tables name in each subclass hierarchy should default to the highest class name and use DefaultNamingStrategy.classToTableName() to generate table names.
****


Top
 Profile  
 
 Post subject: "component friendly" HibernateUtil.java replacemen
PostPosted: Fri Oct 28, 2005 3:39 am 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
If the Hibernate team would fix this issue I'd offer to the source for my "component friendly" replacement for HibernateUtil.java

Cheers,
Tony.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 28, 2005 5:05 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
So in short you need "Table per subclass hierarchy"
"What the framework pattern needs is support for "Table per subclass hierarchy" with a single table used for the base class and lazy loading of the subclass fields."
http://www.hibernate.org/hib_docs/v3/re ... leperclass
Do you have problems with this mapping ?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 28, 2005 6:41 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
A couple of misunderstandings:

1) I think you missed the point of table per class hierarchy (option #1). The other term used there is "discriminator subclassing". = no joining required as the data is all in one table...

2) adding a fetch option to <joined-subclass/> will not do what I think you think it will do. Hibernate would still need to go hit all the defined subclass tables to resolve any row in the superclass table. It seems like you are thinking it would somehow know which subclass table to "go hit" based on the information from the superclass table; obviously that is not the case.

3) fetch="select" does not mean lazy loading!

4) Hibernate could lazily load the properties specific to a subclass, but that would require build-time byte code manipulation (which is an option).

Regardless, I don't think what you are saying is totally unreasonable. You can add an enhancement request to JIRA if you want. I will not have time to get to it anytime soon. You could also look at implementing this functionality yourself and submitting a patch. Each of these inheritence strategies are implemented by the different EntityPersister implementations; so this would require a new persister implementation.


Top
 Profile  
 
 Post subject: Table per subclass heirarchy needed
PostPosted: Mon Oct 31, 2005 3:01 am 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
baliukas wrote:
So in short you need "Table per subclass hierarchy"
"What the framework pattern needs is support for "Table per subclass hierarchy" with a single table used for the base class and lazy loading of the subclass fields."
http://www.hibernate.org/hib_docs/v3/re ... leperclass
Do you have problems with this mapping ?


Thanks for your interest and response.

No unfortunately this mapping implements table per inheritance heirarchy which does not solve my problem.

Potentially large numbers of extension components and derived classes may be implemented by different authors. Field names in these derived classes can easily be the same - resulting name collisions that are forbidden by the current table per class hierarchy implemention.

The Framework API needs to efficiently search and load base class instance fields so it's best to store these common fields in one table. The core framework classes do not use most of the fields used in derived classes implemented by extension components so its best that these fields be lazy loaded and stored in separate tables (one per component).

Components often create derived class hierarchies so one table per subclass hierarchy is optimal. Field names with these subclass heirarchies controlled by a single component author so field naming collisions can be avoided.

A table per subclass heirarchy is required with a default name based on the highest class in each subclass heirarchy. In other words, the Hibernate OR mapping should allow classes to inherit or override thier table (and related OR properties) - just like any other inherited runtime property or method.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 31, 2005 3:41 am 
Newbie

Joined: Sun Jan 30, 2005 9:43 pm
Posts: 16
steve wrote:
A couple of misunderstandings:

1) I think you missed the point of table per class hierarchy (option #1). The other term used there is "discriminator subclassing". = no joining required as the data is all in one table...

2) adding a fetch option to <joined-subclass/> will not do what I think you think it will do. Hibernate would still need to go hit all the defined subclass tables to resolve any row in the superclass table. It seems like you are thinking it would somehow know which subclass table to "go hit" based on the information from the superclass table; obviously that is not the case.

3) fetch="select" does not mean lazy loading!

4) Hibernate could lazily load the properties specific to a subclass, but that would require build-time byte code manipulation (which is an option).

Regardless, I don't think what you are saying is totally unreasonable. You can add an enhancement request to JIRA if you want. I will not have time to get to it anytime soon. You could also look at implementing this functionality yourself and submitting a patch. Each of these inheritence strategies are implemented by the different EntityPersister implementations; so this would require a new persister implementation.


Thanks for your the corrections Steve. I'm sure I still have lots more of Hibernate to master.

I'd don't think that time or my skill level with Hibernate would permit me to perform this patch at the moment. Though it would be fun :) The best I can offer to the Hibernate community is the component friendly version of HibernateUtil.

When I discovered this problem it cost me 2 weeks of fixing and testing to replace class inheritance with a class association hack. It's annoyingly still biting at my heels but I can live with it for a few months yet. I dread to think what reversing this hack will cost me now but its mostly warping what will eventually be generated code. There are however some nasty gotchas on the horizon related to dynamic HQL queries that I don't want to have to contemplate HQL parsing to repair. Its definately a design pimple that needs extermination on an otherwise delightful gal ;) .


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.