Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA中的深度复制_Java_Jpa - Fatal编程技术网

Java JPA中的深度复制

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

我想做一份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 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();