我想在JPA中制作一个实体的深层副本。我在这里找到了一个有趣的讨论 http://forums.java.net/jive/thread.jspa?messageID=253092&tstart=0
听起来建议的解决方案是将所有@ 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代码,他们可以共享???
谢谢!
答案 0 :(得分:3)
我不确定是否将已管理对象的ID清零是一个好主意,尤其是。当您的实体没有将equals()
定义为ID相等时。 JPA实现可能已经将托管对象放在某个缓存中,并且在使用那里的对象ID时去了beserk。
我相信按照R.K.的回答并真正复制对象会更安全。
答案 1 :(得分:3)
我解决了这个问题。
我创建了一个组件,根据包的注释(javax.persistence
)为您完成整个过程。
组件已将实体的id设置为null。他根据每个属性关系@OneToMany
,@OneToOne
或@ManyToMany
的类型对要应用的算法进行所有分析。
示例强>
Person person = personDAO.find(1);
PersistenceCloner cloner = new PersistenceCloner(person);
Person personCopy = cloner.generateCopyToPersist();
下载 JAR和来源:jpa-entitycloner
答案 2 :(得分:2)
如果您的对象实现了Serializable,则可以使用writeObject()和readObject()来进行深层复制。我们有一个数据传输对象层次结构,并通过抽象超类(DTO)中的此方法支持深层副本:
/**
* Reply a deep copy of this DTO. This generic method works for any DTO subclass:
*
* Person person = new Person();
* Person copy = person.deepCopy();
*
* Note: Using Java serialization is easy, but can be expensive. Use with care.
*
* @return A deep copy of this DTO.
*/
@SuppressWarnings("unchecked")
public <T extends DTO> T deepCopy()
{
try
{
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
return (T) ois.readObject();
}
finally
{
oos.close();
ois.close();
}
}
catch ( ClassNotFoundException cnfe )
{
// Impossible, since both sides deal in the same loaded classes.
return null;
}
catch ( IOException ioe )
{
// This has to be "impossible", given that oos and ois wrap a *byte array*.
return null;
}
}
(我确信有人会找到
其他序列化库(例如,XStream)可以以相同的方式使用。
答案 3 :(得分:2)
我能够按照问题中的描述获得深层拷贝。有必要急切加载整个图形并将@ Id重置为null或零。我发现Hibernate SessionFactory实际上有方法来帮助这个过程。
以上针对深层复制的其他建议似乎不起作用。当然,问题可能出在键盘和椅子之间。但它现在正在运作。
谢谢大家!
答案 4 :(得分:1)
你为什么要这样做?这听起来有点像黑客攻击。
说 Apache Commons BeanUtils 包含cloneBean()
和copyProperties()
方法来制作(浅层)对象副本。要制作深层副本,您可以按照建议的here编写方法。