Java JPA 中的深度复制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1106632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:50:17  来源:igfitidea点击:

Deep Copy in JPA

javajpa

提问by User1

I would like to make a deep copy of an entity in JPA. I found an interesting discussion here: http://forums.java.net/jive/thread.jspa?messageID=253092&tstart=0

我想在 JPA 中制作一个实体的深层副本。我在这里发现了一个有趣的讨论:http: //forums.java.net/jive/thread.jspa?messageID=253092&tstart=0

It sounded like the proposed solution was to set all @Id's to zero. Here's my basic code:

听起来提议的解决方案是将所有@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();

Is this a good strategy? Might anyone have this TODO code already written that they can share???

这是一个好策略吗?可能有人已经编写了可以共享的 TODO 代码吗???

Thanks!

谢谢!

采纳答案by User1

I was able to get a deep copy to work as described in the question. It is necessary to eagerly load the whole graph and reset the @Id's to null or zero. I found that the Hibernate SessionFactory actually has methods to help with this process.

我能够按照问题中的描述获得深层副本。有必要急切地加载整个图形并将@Id 重置为空或零。我发现 Hibernate SessionFactory 实际上有帮助这个过程的方法。

The other recommendations above for deep copies didn't seem to work. Granted, the problem may have been between keyboard and chair. But it's working now.

上面针对深拷贝的其他建议似乎不起作用。当然,问题可能出在键盘和椅子之间。但它现在正在工作。

Thanks everyone!

谢谢大家!

回答by Richard Kettelerij

Why would you want to do this? It sounds a bit like hacking.

你为什么想做这个?这听起来有点像黑客攻击。

That said Apache Commons BeanUtilscontains cloneBean()and copyProperties()methods to make (shallow) object copies. To make a deep copy you could do write a method as proposed here.

也就是说Apache Commons BeanUtils包含cloneBean()copyProperties()制作(浅)对象副本的方法。要进行深层复制,您可以按照此处的建议编写方法。

回答by Grzegorz Oledzki

I am not really sure if zeroing IDs of already managed objects is a good idea, esp. when your entities don't have equals()defined as equality of IDs. The JPA implementation might have had the managed objects in some cache and go beserk when playing with IDs of objects there.

我不确定将已管理对象的 ID 归零是否是一个好主意,尤其是。当您的实体没有equals()定义为 ID 相等时。JPA 实现可能在某些缓存中具有托管对象,并且在使用那里的对象 ID 时会变得狂暴。

I believe it would be safer to follow R.K.'s answer and do the real copying of objects.

我相信遵循 RK 的回答并真正复制对象会更安全。

回答by Jim Ferrans

If your objects implement Serializable, you can use writeObject() and readObject() to make a deep copy. We have a data transfer object hierarchy and support deep copies via this method in the abstract superclass (DTO):

如果您的对象实现了 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;
    }
}

(I'm certain that someone will find a reason why these exceptions canoccur.)

(我敢肯定有人会觉得为什么这些例外的理由可以发生。)

Other serialization libraries (eg, XStream) could be used in the same manner.

可以以相同的方式使用其他序列化库(例如,XStream)。

回答by Victor Lindberg

I SOLVED THIS.

我解决了这个问题。

I created a component that makes this whole process for you based on the annotations of the package (javax.persistence).

我创建了一个组件,它根据包 ( javax.persistence)的注释为您完成整个过程。

Component already sets the id of the entity to null. He does all the analysis of the algorithm to be applied based on the type of each attribute relationship @OneToMany, @OneToOneor @ManyToMany.

组件已将实体的 id 设置为 null。他做算法的所有分析,根据每个属性关系的类型可以应用@OneToMany@OneToOne@ManyToMany

Example

例子

Person person = personDAO.find(1);
PersistenceCloner cloner = new PersistenceCloner(person); 
Person personCopy = cloner.generateCopyToPersist();

DownloadJAR and SOURCES: jpa-entitycloner

下载JAR 和来源:jpa-entitycloner