Глубокое копирование в JPA - PullRequest
14 голосов
/ 10 июля 2009

Я хотел бы сделать глубокую копию сущности в JPA. Я нашел интересную дискуссию здесь: http://forums.java.net/jive/thread.jspa?messageID=253092&tstart=0

Похоже, что предлагаемое решение было установить все @ Id's на ноль. Вот мой основной код:


//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 ]

3 голосов
/ 24 августа 2013

ЭТО РЕШЕНО.

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

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

Пример

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

Скачать JAR и ИСТОЧНИКИ: jpa-entitycloner

3 голосов
/ 10 июля 2009

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

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

2 голосов
/ 26 августа 2009

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

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

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

2 голосов
/ 10 июля 2009

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

1 голос
/ 10 июля 2009

Почему вы хотите это сделать? Это звучит как взлом.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...