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: insert only subclass row in a table per subclass stategy
PostPosted: Wed Oct 08, 2008 1:44 pm 
Newbie

Joined: Fri Feb 08, 2008 2:41 pm
Posts: 18
I have a superclass that models an existing table called person that already contains data.
There is also a subclass Employee.
Now I want to be able to convert an existing person to an employee.
When saving an employee, Hibernate should check to see if there is a row in both the person and the employee table and then do a corresponding insert. Hibernate should only try to insert a row in the employee table since the person already exists in the person table.

Code:
@Entity
@Table(name = "person", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"person_firstname", "person_lastname"})
})
@Inheritance(strategy = InheritanceType.JOINED)
public class Person implements Serializable {

    private String id;
    private String title;
    private String firstname;
    private String lastname;
    private char gender;
    private String address;
    private String email;
    private String phone;
    private String mobile;
}

@Entity
@Table(name="employee")
@PrimaryKeyJoinColumn(name="employee_id")
public class Employee extends Person {
    private String position;
    private String username;
    private String password;
}

@Entity
@Table(name = "customer")
@PrimaryKeyJoinColumn(name="customer_id")
public class Customer extends Person {
    private Bank bank;
    private String bankAccount;
    private byte[] signature;
    // .....
}


How do I achieve this?

When calling getHibernateTemplate().saveOrUpdate(employee) I get the following:
Code:
11:48:03,835 DEBUG SQL:401 - /* get current state hakim.model.Employee */ select employee_.employee_id, employee_1_.person_address as person2_26_, employee_1_.person_email as person3_26_, employee_1_.person_firstname as person4_26_, employee_1_.person_gender as person5_26_, employee_1_.person_lastname as person6_26_, employee_1_.person_mobile as person7_26_, employee_1_.person_phone as person8_26_, employee_1_.person_title as person9_26_, employee_.password as password27_, employee_.position as position27_, employee_.salary as salary27_, employee_.username as username27_ from employee employee_ inner join person employee_1_ on employee_.employee_id=employee_1_.person_id where employee_.employee_id=?

11:48:03,839 DEBUG SQL:401 - /* insert hakim.model.Employee */ insert into person (person_address, person_email, person_firstname, person_gender, person_lastname, person_mobile, person_phone, person_title, person_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
11:48:03,841  WARN JDBCExceptionReporter:77 - SQL Error: 1062, SQLState: 23000
11:48:03,842 ERROR JDBCExceptionReporter:78 - Duplicate entry '1980112511' for key 1


As you can see Hibernate first tries to insert a row in the table person;
Is it possible to let Hibernate execute two selects (instead of the inner join) when querying the state of Employee (one for the person table and one for the employee table). Hibernate could then see that there is already a row in the person table and only needs to insert a row in the employee table.

When calling getHibernateTemplate().update(employee) however Hibernate only does an inner join select without inserting or updating any data:

Code:
12:31:54,301 DEBUG SQL:401 - /* get current state hakim.model.Employee */ select employee_.employee_id, employee_1_.person_address as person2_26_, employee_1_.person_email as person3_26_, employee_1_.person_firstname as person4_26_, employee_1_.person_gender as person5_26_, employee_1_.person_lastname as person6_26_, employee_1_.person_mobile as person7_26_, employee_1_.person_phone as person8_26_, employee_1_.person_title as person9_26_, employee_.password as password27_, employee_.position as position27_, employee_.salary as salary27_, employee_.username as username27_ from employee employee_ inner join person employee_1_ on employee_.employee_id=employee_1_.person_id where employee_.employee_id=?


One solution would be to delete the already existing person row and insert the employee.
This however is not going to work in my case since the person may already be linked to other data. A person can even be both an employee and a customer.

Please does anyone now a solution for this?


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Tue May 19, 2009 12:46 pm 
Newbie

Joined: Fri May 15, 2009 3:54 pm
Posts: 6
Hi,

I have the same problem, have you found any solution about that yet.

Thank you for any help or hint,
Philippe


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Tue May 19, 2009 12:58 pm 
Newbie

Joined: Fri Feb 08, 2008 2:41 pm
Posts: 18
2 options:

1. You could try using a custom SQL insert statement that will do an update when there is a duplicate entry (in this case for person).

2. Alternatively you could change the relationship to a One-To-One between (in my case) Person and Employee.


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Tue May 19, 2009 3:01 pm 
Newbie

Joined: Fri May 15, 2009 3:54 pm
Posts: 6
ivan2010 wrote:
2. Alternatively you could change the relationship to a One-To-One between (in my case) Person and Employee.


You mean no inheritance ?


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Tue May 19, 2009 4:03 pm 
Newbie

Joined: Fri Feb 08, 2008 2:41 pm
Posts: 18
Yes, no inheritance.

But.... you could do something like this so that you will not break existing code:

Code:
@MappedSuperclass
public abstract class AbstractPerson
        implements Serializable {

    private Person person;
    private String id;

    @Id
    @Column(name = "person_id", length = 20)
    public String getId() {
        return id;
    }

    public void setId(String id) {
        person.setId(id);
        this.id = id;
    }
    @OneToOne(fetch = FetchType.EAGER)
    @PrimaryKeyJoinColumn
    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Transient
    public String getFirstname() {
        return person.getFirstname();
    }

    public void setFirstname(String firstname) {
        person.setFirstname(firstname);
    }
}

@Entity
@Table(name = "customer")
@AttributeOverride(name="id",column=@Column(name="customer_id",length=20))
//Persister(impl=CustomerPersister.class)
public class Customer extends AbstractPerson {
// other properties and getters + setters
}


Notice that the relation between Customer and Person is One-To-One via the mapped superclass.
Then create additional getters and setters in the super class to make the Customer "look" like it inherits properties like firstname (which are really in the Person class). Something like a wrapper for person.


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Wed May 20, 2009 9:23 am 
Newbie

Joined: Fri May 15, 2009 3:54 pm
Posts: 6
Hi,

I have found a third solution to keep the inheritance and dont use sql.

I created a DTO (Data Transfer Object) for the Employee subclass named EmployeeDTO. EmployeeDTO contain all the properties of Employee but none of the superclass Person. And EmployeeDTO use no inheritance. Then i can map it to the table employee and use hibernate to do the save only on Employee.

so my saving is
Code:
   public void saveOrUpdate(Employee employee ) {
      Session sess = currentSession();
      String requete = "select count(*) as nomber from Person p" +
      " where p.cip ='"+employee.getCip()+"'";
      int nomber = ((Long) sess.createQuery(requete).iterate().next()).intValue();
      
      if ( nomber == 0){
         sess.saveOrUpdate(employee );
      }else {
         sess.saveOrUpdate(new EmployeeDTO(employee ));
      }
      

   }


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Wed May 20, 2009 11:05 am 
Newbie

Joined: Fri Feb 08, 2008 2:41 pm
Posts: 18
So you have both EmployeeDTO and the Employee class mapped to the same table.
Did you also test the scenario if you want to delete the employee but keep the person row?

Do you have other classes that extends Person? You might want to see this post viewtopic.php?f=1&t=993874


Top
 Profile  
 
 Post subject: Re: insert only subclass row in a table per subclass stategy
PostPosted: Wed May 20, 2009 12:11 pm 
Newbie

Joined: Fri May 15, 2009 3:54 pm
Posts: 6
ivan2010 wrote:
Did you also test the scenario if you want to delete the employee but keep the person row?

Very good point, I will do it

ivan2010 wrote:
Do you have other classes that extends Person? You might want to see this post viewtopic.php?f=1&t=993874

Hum I didnt know that. I don't have any others subclass now but I probably will soon.
Maybe I should use a abstract superclasse and add a discriminator to the primary key of the superclass table ?
Or maybe i will use your solution seem great too.


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.