Java 如何使用cascade=";复制hibernate集合;全部,删除孤儿“;

Java 如何使用cascade=";复制hibernate集合;全部,删除孤儿“;,java,hibernate,Java,Hibernate,我正在尝试复制一个hibernate实体,如下所示: A a = (A) session.get(A.class, id); session.evict(a); a.setId(null); session.save(a); 但是,这不起作用,我得到以下费用: org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.tes

我正在尝试复制一个hibernate实体,如下所示:

A a = (A) session.get(A.class, id);
session.evict(a);
a.setId(null);
session.save(a);
但是,这不起作用,我得到以下费用:

org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.test.A.B
可以安全地假设发生此错误是因为我在实体a中定义了一个B实体集合:

<list name="B"  table="B" lazy="false" cascade="all,delete-orphan">
    <key column="A_ID" not-null="true"/>
    <index column="X"/>            
    <one-to-many class="com.test.B"/>
</list>


如何能够复制实体a,包括其实体B的集合,而hibernate对此不满意?

没有自动复制这样的对象的方法。通常,复制的对象可能与其他对象相关联,而这些对象又与其他对象相关联,因此最终可能会复制数据库的很大一部分。用于复制的任何工具都需要知道在对象图中的何处停止复制,不复制什么(就Hibernate实体而言,这些实体是ID、版本列和类似实体),等等

然而,您可以利用框架来避免大部分需要手动编写的样板代码

关于集合重新分配问题,您不能将相同的
B
实例集合分配给两个不同的
A
s,因为它在逻辑上是一个
多对多
关联。这也是您需要手动处理的事情,因为它是特定于您的业务用例的


另外,请确保不要在其他实体实例中重复使用来自一个实体实例的相同集合代理,因为Hibernate会在内部将它们绑定到其原始父级-始终在新实例(可能包含也可能不包含相同的元素)中创建新集合。

如果要复制现有实体-修改它-并将其另存为新实体,然后你需要深度复制那个对象。可以通过序列化然后反序列化对象来执行对象的深度复制

public Object deepCopy(Object input) {

    Object output = null;
    try {
        // Writes the object
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(input);

        // Reads the object
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        output = objectInputStream.readObject();

    } catch (Exception e) {
        e.printStackTrace();
    }
    return output;
}

我以前在我的项目中也遇到过同样的问题

对我来说,将列表项的ID设置为null是有效的

// make copy a of aOriginal by using serialisation clone 
a.setId(null);
for (B b : a.getBs()) {
    b.setId(null);
}
session.save(a);
对于克隆体本身,我使用了

原因是,hibernate试图为“复制的”实体“重用”已经保存的列表项。但是这个已经持久化的列表条目链接到一个原始实体。因此,它试图“更改”实体中的列表本身,因为实体已更改。但是,如果列表带有“删除孤立项”注释,则无法更改该列表(您只能修改列表的条目,但不能修改列表本身)。因此抛出异常


如果我将列表条目ID设置为null,它们也将被插入newley。对象层次结构(而不仅仅是主实体)是重复的。因此,不再抛出exeption。

您的hibernate版本是什么?hibernate版本是3.2请澄清:您想在复制的实体中保留集合中的相同元素,还是也要在集合中复制元素?不清楚您的意图是什么,但我很确定所有引用a.id的实体B都可能是当你试图保存一个id为null的A(可能会生成与B实体中的id不同的id)时,我很烦恼@Andremoniy我想要所有内容的新副本,包括集合。