Changing the type of an entity preserving its ID

hibernate, java, persistence

Solution

Hibernate attempts to make persistence as transparent as it possibly can - which means it tries to follow the same principles as normal Java objects. Now, rephrasing your question in Java, you'd get:

How can I convert an instance of B class into an instance of (incompatible) C class?

And you know the answer to that - you can't. You can create a new instance of C and copy necessary attributes, but B will always be B, never C. Thus the answer to your original question is - it cannot be done via JPA or Hibernate API.

However, unlike plain Java, with Hibernate you can cheat :-) `InheritanceType.SINGLE_TABLE` is mapped using `@DiscriminatorColumn` and in order to convert B into C you need to update its value from whatever's specified for B into whatever's specified for C. The trick is - you cannot do it using Hibernate API; you need to do it via plain SQL. You can, however, map this update statement as named SQL query and execute it using Hibernate facilities.

The algorithm, therefore, is:

- Evict B from session if it's there (this is important)

- Execute your named query.

- Load what-is-now-known-as-C using former B's id.

- Update / set attributes as needed.

- Persist C

Problem

I am using hibernate as a persistence layer. There are 2 entities that live in the same table extending one superclass with single table inheritance strategy. ``` @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class A { @Id @GeneratedValue protected Long id; // some common fields for B and C } @Entity public class B extends A { // B-specific fields } @Entity public class C extends A { // C-specific fields } ``` I have an instance of B with id=4. How do I change the type of this instance to C preserving it's ID (4)? ``` B b = em.find(B.class, 4L); C c = convertToC(b); c.setId(b.getId()); em.remove(b); em.persist(c); ``` The code above fails with ``` org.hibernate.PersistentObjectException: detached entity passed to persist: C ``` Is it possible at all?

Original source