Глубокая копия в 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()
для создания (неглубоких) копий объектов. Чтобы сделать глубокую копию, вы можете написать метод, предложенный здесь.