-->
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.  [ 4 posts ] 
Author Message
 Post subject: Hibernate Inheritance - Change Class Type
PostPosted: Tue Mar 06, 2007 7:20 am 
Newbie

Joined: Sun Dec 24, 2006 10:24 pm
Posts: 5
Hi,

Is it possible to change the subclass type of an existing record. If possible, how can I do it?

For example,
I got the one super class A, which has two sub classes B, C. I have an existing record which is type of B, can I change that record to type C?

Must I do it in SQL statement to change the discriminator field?


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 22, 2007 11:56 am 
Beginner
Beginner

Joined: Wed Feb 25, 2004 6:23 pm
Posts: 39
I have a friend who just ran into this same thing. One idea I had, which is a bit of a hack and completely untested by myself, is this - oh, and it assumes a "single table per class hierarchy":

1. This is the important step! If you've loaded the object whose type you want to change from the current Hibernate session, then EVICT it (using the 'evict(Object)' method in Hibernate's Session interface).
NOTE: you may have to tweak your "cascade" settings if you need the EVICT to cascade down any relationships from your object.
NOTE 2: evict will cause you to lose any unsaved changes to the object.
2. Use an HQL query to update the discriminator:
session.createQuery("update MyObjectType set discriminator = :newType where id = :id").setString("newType", newTypeDiscriminator).setLong("id", idToChange).executeUpdate();
NOTE: if an HQL query doesn't work, then try using a SQLQuery (see the "createSQLQuery" method). If SQLQuery doesn't work, then get the underlying JDBC connection via Session's 'connection()' method and use raw SQL.
3. Maybe EVICT the object again, just to be on the safe side? You probably don't have to do this a second time, but I would experiment to be sure.
In fact, Hibernate may throw an exception if the object is not loaded in the session? Again, experiment and see. :)
4. (optional step, only if things don't work): close the Session and reopen it.
5. Load the new object with the new type: session.get([NewPageType].class, idToChange);

I would love to know if this works. Try and it and tell us what happens. :)


Top
 Profile  
 
 Post subject: Well it actually worked!
PostPosted: Sat Jun 16, 2007 6:18 pm 
Newbie

Joined: Tue Sep 16, 2003 3:26 pm
Posts: 8
It works! Here is my tested code. I'm doing a session.flush(), assuming database changes need to be applied before trying to pull the object again.

Code:
    public static <T> T changeObjectType(
            Session session, T object, Long id,
            Class<T> genericType, String idColumn,
            String discriminatorColumn, String discriminatorValue) {
        session.evict(object);
        Query query = session.createQuery(
            "update " + genericType.getName() + " " +
            "set " + discriminatorColumn + " = :newType " +
            "where " + idColumn + " = :id)");
        query.setLong("id", id);
        query.setString("newType", discriminatorValue);
        query.executeUpdate();
        session.flush();
        object = (T) session.get(genericType, id);
        return object;
    }


Though it would be way better to have a session.changeType(Object obj, Class newType). Much more portable. If anyone dares to post it as a JIRA issue for that, go ahead.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 26, 2007 5:42 am 
Newbie

Joined: Tue Jun 26, 2007 4:36 am
Posts: 2
Hi,


I believe the following HQL will do what you want to do:


Code:
update GenericClass g set g.class = SpecificClass where g.id = :id



Warning:

This does not work at all with the joined-subclass scheme. If you are using the table-per-subclass scheme, you will end up orphaning your record in the class_a_details table should you switch your discriminator to class B. Everything will still function correctly, but your id will exist in both class_a_details and class_b_details with only the parent class's discriminator value serving to identify which implementation applies.

Ideally, a class change would delete the old subclass's detail record and insert a record in the new subclass's detail table, but I don't think such logic exists yet.


bart


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.