JPA中的深层复制

时间:2009-07-09 21:49:40

标签: java jpa

我想在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代码,他们可以共享???

谢谢!

5 个答案:

答案 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编写方法。