Я работаю над проектом Java, и мне нужно написать новый модуль для копирования некоторых данных из одной базы данных в другую (те же таблицы).
У меня есть объект Contrat, содержащий несколько полей и следующее поле:
@OneToMany(mappedBy = "contrat", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
@Cascade( { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
@BatchSize(size = 50)
private Set<MonElement> elements = new HashSet<MonElement>();
Я должен прочитать некоторые объекты "Contrat" из базы данных и записать их в другую базу данных.
Я колеблюсь между 2 решениями:
- используйте jdbc, чтобы запросить первую базу данных и получить объекты, а затем записать эти объекты во вторую базу данных (обращая внимание на порядок и различные ключи). Это будет долго.
- , так как проект в настоящее время использует Hibernate и содержит все классы отображения hibernate, я думал об открытии первого сеанса для первой базы данных, чтении объекта Contrat hibernate, установке нулевых идентификаторов в дочерних элементах и записи объекта в база данных назначения со вторым сеансом. Это должно быть быстрее.
Я написал тестовый класс для второго варианта использования, и процесс завершился неудачей со следующим исключением:
org.hibernate.HibernateException: Don't change the reference to a
collection with cascade="all-delete-orphan"
Я думаю, что ссылка должна измениться, когда я установил для идентификаторов значение null, но я не уверен: я не понимаю, как изменение поля члена коллекции может изменить ссылку на коллекцию
Обратите внимание, что если я удаляю DELETE_ORPHAN из конфигурации, все работает, все объекты и их зависимости записываются в базу данных.
Поэтому я хотел бы использовать решение гибернации, которое работает быстрее, но я должен сохранить функцию DELETE_ORPHAN, потому что приложение в настоящее время использует эту функцию, чтобы гарантировать, что каждый MonElement, удаленный из набора элементов, будет удален в базе данных.
Мне не нужна эта функция, но я не могу ее удалить.
Кроме того, мне нужно установить нулевые идентификаторы MonElement, чтобы генерировать новые, поскольку их идентификаторы в первой базе данных могут существовать в целевой базе данных.
Вот код, который я написал, который хорошо работает, когда я удаляю опцию DELETE_ORPHAN.
SessionFactory sessionFactory = new AnnotationConfiguration().configure("/hibernate.cfg.src.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
// search the Contrat object
Criteria crit = session.createCriteria(Contrat.class);
CriteriaUtil.addEqualCriteria(crit, "column", "65465454");
Contrat contrat = (Contrat)crit.list().get(0);
session.close();
SessionFactory sessionFactoryDest = new AnnotationConfiguration().configure("/hibernate.cfg.dest.xml").buildSessionFactory();
Session sessionDest = sessionFactoryDest.openSession();
Transaction transaction = sessionDest.beginTransaction();
// setting id to null, also for the elements in the elements Set
contrat.setId(null);
for (MonElement element:contrat.getElements()) {
element.setId(null);
}
// writing the object in the database
sessionDest.save(contrat);
transaction.commit();
sessionDest.flush();
sessionDest.close();
Это намного быстрее, чем управлять своими запросами, первичными / внешними ключами и зависимостями между объектами.
У кого-нибудь есть идея избавиться от этого исключения?
Или, может быть, я должен изменить состояние набора.
На самом деле я не пытаюсь удалить какой-либо элемент этого набора, я просто хочу, чтобы они рассматривались как новые объекты.
Если я не найду решение, я сделаю что-то грязное: продублирую все объекты спящего объекта в моем новом проекте и удалим параметр DELETE_ORPHAN во вновь созданном Контрасте.
Таким образом, приложение будет продолжать использовать свое отображение, а мой новый проект будет использовать мое конкретное отображение. Но я хочу этого избежать.
Спасибо