Глубокая копия в 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 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 написал, что они могут делиться???

Спасибо!

Ответы

Ответ 1

Я смог получить глубокую копию для работы, как описано в вопросе. Необходимо с нетерпением загрузить весь график и reset значение @Id в нуль или ноль. Я обнаружил, что у Hibernate SessionFactory есть методы, помогающие в этом процессе.

Другие рекомендации, приведенные выше для глубоких копий, как представляется, не работают. Конечно, проблема могла быть между клавиатурой и стулом. Но теперь он работает.

Спасибо всем!

Ответ 2

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

Я считаю, что было бы безопаснее следовать за Р.К. отвечать и выполнять реальное копирование объектов.

Ответ 3

Я РЕШЕН ЭТО.

Я создал компонент, который делает весь этот процесс для вас на основе аннотаций пакета (javax.persistence).

Компонент уже устанавливает id объекта в null. Он выполняет весь анализ применяемого алгоритма на основе типа отношения каждого атрибута @OneToMany, @OneToOne или @ManyToMany.

Пример

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

Загрузите JAR и SOURCES: jpa-entitycloner

Ответ 4

Если ваши объекты реализуют 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).

Ответ 5

Зачем вам это нужно? Это похоже на взлом.

Тем не менее Apache Commons BeanUtils содержит методы cloneBean() и copyProperties() для создания (неглубоких) копий объектов. Чтобы сделать глубокую копию, вы можете написать метод, предложенный здесь.