Hi all,
Hibernate 3.6.5.Final, MySQL 5.5, JDK 1.7.
I've extended an Entity to have a new child class using the JOINED inheritance strategy, and tried to migrate data in using low level SQL (a Liquibase changelog) rather than Java code to create the database rows for the Entities. I find that fetching these migrated entities fails to recognise them as specialised types. For example, ChildEntity is derived from ItemEntity, and when I fetch an ItemEntity with:
Code:
ItemEntity i = (ItemEntity)session.load(ItemEntity.class, "the_id");
A ChildEntity created via Java and persisted by Hibernate is fetched as a ChildEntity instance, and I can see Hibernate generate SQL with a JOIN between the two tables, as expected. However, a ChildEntity manually inserted by me is fetched as a plain ItemEntity. My question is about how to manually insert data so that Hibernate can fetch it as a ChildEntity instance.
Some Background:
-----------------------
I have a data model I've used for a few years with a simple @MappedSuperclass and single concrete Entity class, backed by a single table. Very simple. Here's some example pseudocode (not necessarily precisely correct).
Code:
@MappedSuperclass
public class AbstractPersistentEntity implements Serializable {
@Id
int id;
}
@Entity
@Table(name="items")
public class ItemEntity extends AbstractPersistentEntity {
@Column(name="item_attr")
String itemAttribute;
}
Based on that, I have a single table in the database called "items":
Code:
TABLE items ( id INTEGER PRIMARY KEY, item_attr VARCHAR(255) );
The New ChildEntity Class
--------------------------------
Now I've introduced ChildEntity. I find I have to specify an InheritanceStrategory for ItemEntity, where I didn't before:
Code:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="items")
.. as before
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="items_child")
public class ChildEntity extends ItemEntity {
@Column
String child_attr;
}
If I let hbm2ddl create the database schema I get:
Code:
TABLE items ( id INTEGER PRIMARY KEY NOT NULL, item_attr VARCHAR(255) );
TABLE items_child ( id INTEGER PRIMARY KEY NOT NULL, child_attr VARCHAR(255) );
Since the "items" table already existed, my migration task is to populate "items_child" with suitable attributes so the ChildEntity entities are complete.
Code:
INSERT INTO items_child (id, child_attr)
SELECT i.id, at.attributes
FROM items i
INNER JOIN some_data_source at ON at.join_key = i.id
WHERE at.something = 'value';
This works fine and I can see the "items_child" rows created, with id's matching those in "items", but I'm missing some magic sauce that Hibernate seems to need, because no session.load(ItemEntity.class, "the_id") calls will fetch them as ChildEntity instances.
If I use the single table inheritance strategy, hbm2ddl creates a DTYPE column with the entity type clearly expressed, but I cannot see how the same information is expressed when using the joined strategy. I have a small test project with just the two entities in a cleanroom database, and cannot see how Hibernate knows which are ItemEntity instances and which are ChildEntity instances.
Can anyone suggest what I'm missing, what FAQ I haven't read, or what pieces of magic eludes me? Or would posting some actual code here help?
If I cannot crack this, I'm going to resort to writing the migration code in Java and let Hibernate do its persistence magic, but that would defeat the purpose of using Liquibase as a database change tracking tool, which forces me to use low level SQL to do the job. That will be some time next week, or the week after.
Many Thanks
Nick