package uidreuse; import java.util.List; import javax.persistence.Basic; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.FlushModeType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Persistence; public final class Example { static int idCounter = 1; public static void main(String[] args) { createDB(); // add breakpoint and check the Database -> everything OK updateDB(); // now the reference from entityA2 to entityB2 is 'broken' // demonstrate the error validateDB(); } private static void createDB() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test.tmp;drop"); EntityManager em = emf.createEntityManager(); em.setFlushMode(FlushModeType.AUTO); em.getTransaction().begin(); EntityB entityB1 = new EntityB(1); entityB1.kind = null; entityB1.anyField = "B1"; em.persist(entityB1); EntityB entityB2 = new EntityB(2); entityB1.kind = "X"; entityB1.anyField = "B2"; em.persist(entityB2); EntityA entityA1 = new EntityA(101); entityA1.reference = entityB1; em.persist(entityA1); EntityA entityA2 = new EntityA(102); entityA2.reference = entityB2; em.persist(entityA2); em.getTransaction().commit(); emf.close(); } private static void updateDB() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test.tmp"); EntityManager em = emf.createEntityManager(); em.setFlushMode(FlushModeType.AUTO); em.getTransaction().begin(); // covert (we call this step migrate) all EntityB's with a value in // 'kind' to new Type NewKindOfEntityB @SuppressWarnings("unchecked") List entityBs = em.createQuery("Select FROM EntityB ").getResultList(); for (EntityB entityB : entityBs) { if (entityB.kind != null) { // convert Type! AND reuse the ID NewKindOfEntityB newKindOfEntityB = new NewKindOfEntityB(entityB.id); newKindOfEntityB.kind = entityB.kind; newKindOfEntityB.anyField = entityB.anyField; newKindOfEntityB.additionalField = "converted from Type B"; em.remove(entityB); // flush that we get NO conflict in the 'MasterEntity' table! em.flush(); em.persist(newKindOfEntityB); } } em.getTransaction().commit(); emf.close(); } private static void validateDB() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test.tmp"); EntityManager em = emf.createEntityManager(); em.setFlushMode(FlushModeType.AUTO); em.getTransaction().begin(); @SuppressWarnings("unchecked") List entityAs = em.createQuery("Select FROM EntityA").getResultList(); for (EntityA entityA : entityAs) { EntityB ref = entityA.reference; if (ref.id == 1) { if (!(ref.getClass().equals(EntityB.class))) { throw new RuntimeException("unexpected Type"); } } if (ref.id == 2) { if (ref.anyField == null) { System.out.println("ref.anyField is null, but the value B2 is expected"); } if (!(ref.getClass().equals(NewKindOfEntityB.class))) { System.out.println("unexpected Type for ID: " + ref.id); } } } em.getTransaction().commit(); emf.close(); } @Entity public static abstract class MasterEntity { public MasterEntity() { } public MasterEntity(int id) { this.id = id; } @Id int id; } @Entity public static class EntityA extends MasterEntity { public EntityA() { } public EntityA(int id) { super(id); } @OneToOne EntityB reference; } @Entity public static class EntityB extends MasterEntity { public EntityB() { } public EntityB(int id) { super(id); } @Basic String kind; @Basic String anyField; } @Entity public static class NewKindOfEntityB extends EntityB { public NewKindOfEntityB() { } public NewKindOfEntityB(int id) { super(id); } @Basic String additionalField; } }