如何使用openjpa将实体从一个数据库移动到另一个数据库?

时间:2014-04-14 13:54:51

标签: java java-ee jpa openjpa

我试图将实体对象从一个数据库移动到另一个数据库但没有成功。示例代码:

EntityManagerFactory emfFrom = Persistence.createEntityManagerFactory(fromPU);
EntityManager emFrom = emfFrom.createEntityManager();

EntityManagerFactory emfTo = Persistence.createEntityManagerFactory(toPU);
EntityManager emTo = emfTo.createEntityManager();

//Code to create sql for example 'select row from order row' where order is an entity

Query q = emFrom.createQuery(sql);
for(Object o: q.getResultList()) {
   emFrom.detach(o);
   emTo.persist(entity);
}

这导致:

  

线程“main”中的异常> org.apache.openjpa.persistence.EntityExistsException:尝试持久保存分离的对象“Order-1”。如果这是一个新实例,请确保持久化时任何版本和/或自动生成的主键字段为null / default。   失败对象:订单-1     在org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2628)     在org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2571)     在org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2554)     在org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2458)     在org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1077)     在org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:716)

我尝试使用merge而不是persist,但数据库中没有保存任何行。我还尝试使用反射(因为它的私有)将id字段设置为null,如下所示:

Field f = o.getClass().getDeclaredField("id");
f.setAccessible(true);
f.set(o, null);

但没有运气。我无法将版本字段设置为null,因为它很长,而id字段为Long。我不知道这是否会有所帮助。

我正在使用java 7和openjpa 2.2。关于如何移动实体的任何想法都会很棒。感谢。

2 个答案:

答案 0 :(得分:0)

您的JPA提供程序令人困惑,因为它会将您的实体包装在一个代理中,其中包含详细说明它与数据库相关的状态的信息(例如,它知道它已成功加载并且未被修改)所以调用'保存'使用不同的底层数据库是没有意义的。

您需要创建对象的副本(实际上是逐个字段),然后保留它,以便您的JPA提供程序认为它是插入,而不是更新。

现在你可能会说你不想复制每个字段 - 它容易出错,需要一段时间。一个好方法是转换为JSON然后再次返回到新对象。

看看Googles GSON:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.2.4</version>
</dependency>

例如:

final SomeEntity oldInstance = new SomeEntity("hello");
final Gson gson = new Gson();
final String json = gson.toJson(oldInstance);
final SomeEntity newInstance = gson.fromJson(json, oldInstance.getClass());

您需要getter / setter和非final字段才能执行此操作,因为JSON图书馆会对类使用反射,否则您将不得不手工编写某种类型的复制构造函数或构建器来逐字段地执行此操作

答案 1 :(得分:0)

我遇到了同样的问题,我找到了两个解决方案。
第一:清除 OpenJPA 状态

/*
 * Method 1 : clear OpenJPA State
 */
 Field field = car.getClass().getDeclaredField("pcStateManager");
 field.setAccessible(true);
 field.set(car, null);
 car.setId(null);
 EntityTransaction transaction = entityManager.getTransaction();
 transaction.begin();
 entityManager.persist(car);
 transaction.commit();

在第二种解决方案中,您可以使用推土机并创建实体的新实例,请记住在映射实体实例时必须排除 @Id 字段

List<String> mappingFiles = new ArrayList<String>();
mappingFiles.add("dozer-mappings.xml");
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setMappingFiles(mappingFiles);

您可以在我的 Github sample

上找到有关解决方案的更多详细信息