Java JPA中的深度复制
我想做一份JPA实体的深度副本。我在这里发现了一个有趣的讨论: 听起来提议的解决方案是将所有@Id设置为零。这是我的基本代码:Java JPA中的深度复制,java,jpa,Java,Jpa,我想做一份JPA实体的深度副本。我在这里发现了一个有趣的讨论: 听起来提议的解决方案是将所有@Id设置为零。这是我的基本代码: //Start a JPA session. EntityManager em= emf.createEntityManager(); em.getTransaction().begin(); //Get the object I want to copy. MyClass myObject=em.find(MyClass.class,id); //Use re
//Start a JPA session.
EntityManager em= emf.createEntityManager();
em.getTransaction().begin();
//Get the object I want to copy.
MyClass myObject=em.find(MyClass.class,id);
//Use reflection to find @Id's and set them to zero for all @OneToMany and @OneToOne relations.
//TODO: write the ugly recursive code to do this.
//Hoping this will create a deep copy.
em.merge(myObject);
//Close the session.
em.getTransaction().commit();
em.close();
这是一个好策略吗?可能有人已经编写了这个TODO代码,可以共享吗
谢谢 你为什么要这样做?听起来有点像黑客
也就是说,Apache Commons BeanUtils包含
cloneBean()
和copyProperties()
方法来创建(浅层)对象副本。要制作深度复制,您可以按照建议编写一个方法。我不确定将已管理对象的ID归零是否是一个好主意,尤其是当您的实体没有定义为ID相等的equals()
时。JPA实现可能在某些缓存中有托管对象,并且在那里玩对象ID时会变得非常糟糕
我相信按照R.K.的答案进行真正的对象复制会更安全。如果您的对象实现可序列化,您可以使用writeObject()和readObject()进行深度复制。我们有一个数据传输对象层次结构,并在抽象超类(DTO)中通过此方法支持深度拷贝:
/**
*回复此DTO的深度副本。此通用方法适用于任何DTO子类:
*
*Person=新人();
*Person copy=Person.deepCopy();
*
*注意:使用Java序列化很容易,但可能很昂贵。小心使用。
*
*@返回此DTO的深度副本。
*/
@抑制警告(“未选中”)
公共T-deepCopy()
{
尝试
{
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
尝试
{
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
oos=新对象输出流(bos);
oos.writeObject(本);
oos.flush();
ois=newObjectInputStream(newbytearrayinputstream(bos.toByteArray());
返回(T)ois.readObject();
}
最后
{
oos.close();
ois.close();
}
}
捕获(ClassNotFoundException cnfe)
{
//不可能,因为双方都处理相同的加载类。
返回null;
}
捕获(ioe异常ioe)
{
//这必须是“不可能的”,因为oos和ois包装了一个*字节数组*。
返回null;
}
}
(我相信有人会找到这些异常发生的原因。)
其他序列化库(如XStream)也可以以同样的方式使用。我能够获得一个深度副本,以便按照问题中的描述工作。有必要急切地加载整个图形,并将@Id重置为null或零。我发现Hibernate SessionFactory实际上有一些方法可以帮助完成这个过程 上面关于深度拷贝的其他建议似乎不起作用。当然,问题可能出在键盘和椅子之间。但它现在起作用了
谢谢大家 我解决了这个问题。 我创建了一个组件,它基于包的注释为您完成整个过程(
javax.persistence
)
组件已将实体的id设置为null。他根据每个属性关系的类型对要应用的算法进行所有分析
示例
Person person = personDAO.find(1);
PersistenceCloner cloner = new PersistenceCloner(person);
Person personCopy = cloner.generateCopyToPersist();
下载JAR和源代码:我想对存储在数据库中的数据进行深度复制,这些数据将完全独立于从中复制数据的对象。例如:-Object1是Object2的深层副本-Object1的子对象(来自@OneToMany)发生了更改-Object2的子对象不应更改。对于deepCopy,您可以使用apache Commons中的SerializationUtils.clone()。这不会复制标记为transient关键字的字段。@Sean:谢谢,这是一个很好的观点。(在我们的例子中,这些是香草JavaBeans。)@Sean:因为瞬态字段也不会出现在DB中,所以这似乎是正确的行为。同意。我曾参与过几个项目,在这些项目中,我们试图找到一种通用的方法来制作对象图的深度副本。随着项目的发展,您经常遇到的问题是,您最终需要为不同的用例和/或对象中的不同属性集复制对象图的不同部分。最终,只需要自己编写逻辑,而不需要尝试通过自动深度克隆变得聪明,这会变得更容易。此外,删除ID几乎肯定会破坏一些JPA实现。基本上,您说过我们需要急切地加载整个图,但我们的图并不经常初始化集合。您还评论说SessionFactory有一些方法可以帮助重置@id的过程。你能提供一些代码示例吗,因为我面临着同样的问题,这让我发疯:)但你没有提供一段代码。哪个Hibernate SessionFactory方法使其链接断开。你能更新它吗?你确定要进行深度复制吗?这可能导致整个数据库被复制。我宁愿坚持实现复制——这很乏味,但可以让我省去头痛,或者更糟的是,让服务器在生产中崩溃。
Person person = personDAO.find(1);
PersistenceCloner cloner = new PersistenceCloner(person);
Person personCopy = cloner.generateCopyToPersist();