Подтвердить что ты не робот

Как сделать копию коллекции спящего режима с помощью cascade = "all, delete-orphan"

Я пытаюсь сделать копию объекта спящего режима A следующим образом:

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

Безопасно предположить, что эта ошибка происходит из-за того, что у меня есть совокупность объекта B, определенного в сущности A:

<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 без спящего режима, которая была недовольна этим?

4b9b3361

Ответ 1

У меня была такая же проблема ранее в моем проекте.

Для меня это работает, чтобы установить идентификатор списка-записей в значение null.

// make copy a of aOriginal by using serialisation clone 
a.setId(null);
for (B b : a.getBs()) {
    b.setId(null);
}
session.save(a);

Для самого клона я использовал Apache SerializationUtils clone.

Причина в том, что hibernate пытается "повторно использовать" уже сохраненные записи списка для "скопированного" объекта. Но эти уже сохраненные записи списка связаны с исходным объектом. Поэтому он пытается "изменить" сам список в сущности, потому что сущность изменилась. Но вы не можете изменить список, если он аннотируется с помощью "delete-orphans" (вы можете только изменить записи списка, но не сам список). Таким образом, исключение выбрано.

Если я установил идентификаторы списка-списка равными нулю, они также будут вставлены newley. И иерархия объектов (а не только основная сущность) дублируется. Таким образом, освобождение больше не бросается.

Ответ 2

Нет автоматического способа копирования таких объектов. В общем случае скопированный объект может быть связан с другими объектами, которые в дальнейшем связаны с другими объектами и т.д., Поэтому вы можете копировать большую часть базы данных. Любой инструмент, который вы используете для копирования, должен знать, где в графе объектов прекратить копирование, что не копировать (в терминах объектов Hibernate - это идентификаторы, столбцы версий и т.д.) И т.д.

Однако вы можете использовать фреймворки, такие как Dozer, чтобы избежать большей части кода шаблона, который вам нужно будет писать вручную.

Что касается проблемы переназначения коллекции, вы не можете иметь один и тот же набор экземпляров B, назначаемых двум различным A s, так как это логически является ассоциацией many-to-many. Это также то, что вам нужно будет позаботиться вручную, так как оно специфично для вашего бизнес-использования.

Кроме того, убедитесь, что вы не повторно используете одни и те же прокси файлы из одного экземпляра объекта в других, поскольку Hibernate связывает их со своими родителями внутри себя - всегда создавайте новую коллекцию в новых экземплярах (которые могут содержать или не содержать одинаковые элементы).

Ответ 3

Если вы хотите скопировать существующий объект - изменить его - и сохранить его как новый объект, то вам нужно глубоко скопировать этот объект. Вы можете выполнить глубокую копию объекта путем сериализации, а затем де-сериализовать этот объект.

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;
}