views:

506

answers:

3

Hi folks,

my question is very similar to http://stackoverflow.com/questions/1118873/changing-the-type-of-an-entity-preserving-its-id, but instead i´m using InheritanceType.JOINED instead of Table_per_class.

This means i don´t to change any table, just to create a new subclass, with the same id as the superclass.

To summarize, I have a Person class and a Doctor, which extends Person and has the same id of it. I need to retrieve a Person from the database and make it a Doctor, preserving all the data from the Person entity, but creating some extra data for the Doctor one.

Trying to merge the doctor generates a new id, which is not valid for me.

Here´s what i´ve tried in first place

private Person getDoctor(Person person) {
            // Person already a doctor ==> OK
 if (person instanceof Doctor) {
  return person;
 }
            // Transient Person ==> //Transient Doctor OK
 if (person == null) {
  return new Doctor();
 }
            // Creates a Doctor from the person (only setting id...),
            // and merges it ==>
            fails as the id changes.
 Doctor doctor = new Doctor(person);
 return personDAO.merge(doctor);
}

Tks.

A: 
sorry guys,first time here.

Here´s the code above:

    private Person getDoctor(Person person) {
    //Person already a doctor ==> OK 
       if (person instanceof Doctor) { 
            return person; 
    }


     //Transient Person ==> //Transient Doctor OK
        if (person == null) {
         return new Doctor(); 
        }
    //Creates a Doctor from the person (only setting id...), and merges it ==> fails as the id changes. 
    Doctor doctor = new Doctor(person);
    return personDAO.merge(doctor); 
    }


   @Inheritance(strategy = InheritanceType.JOINED)
   @Entity
   public class Person{
   }

   @Entity
   public class Doctor extends Person{
      public Doctor(Person person) {
     if (person != null) {
      this.setId(person.getId());
     }
    }
   }
Luiz Henrique Martins Lins Rol
+2  A: 

Just like in the question you've linked to, the answer is "you can't do this using Hibernate API".

The reason is actually quite clear - Hibernate aims to make persistence as transparent as possible and, therefore, can't allow you do to things with persistent objects that you wouldn't be able to do with normal Java ones. Once you create an instance of Person (in plain java), it's always a Person. It will NEVER be a Doctor. The best you can do is to create a Doctor instance and copy Person's attributes to it.

Unlike plain java, however, with Hibernate you can cheat and achieve what you want :-) but it has to be done via native SQL. In your method you'll need to:

  1. Evict Person instance from session (and 2nd level cache if applicable)
  2. Insert a row with matching ID (taken from Person instance) into Doctors table. That's the part that has to be done as native sql, but you can define it as named query and set the above id as parameter. Note that if have any constraints on Doctor properties, you'll need to make sure the values you insert satisfy them.
  3. Reload Person instance - which will now be loaded as Doctor.
ChssPly76
A: 

Sorry fot taking so long to answer, i was kind busy here.

Just to confirm your solution did work!

Thank you very much!!!

PS: I could not use a named query, as the id property is mapped in the Person entity. Instead, i used a nativeQuery.

Explanation taken from : http://docs.jboss.org/hibernate/stable/core/reference/en/html/batch.html#batch-direct

Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form. The properties_list is analogous to the column specification in the SQL INSERT statement. For entities involved in mapped inheritance, only properties directly defined on that given class-level can be used in the properties_list. Superclass properties are not allowed and subclass properties do not make sense. In other words, INSERT statements are inherently non-polymorphic.

Luiz Henrique Martins Lins Rol