我从事一个 Java 项目,我必须编写一个新模块才能将一些数据从一个数据库复制到另一个数据库(相同的表)。
我有一个包含多个字段和以下字段的实体契约(Contract):
@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”对象并将它们写入另一个数据库中。
我在两种解决方案之间犹豫:
- 使用jdbc查询第一个数据库并获取对象,然后将这些对象写入第二个数据库(注意顺序和不同的键)。会很长。
- 由于该项目当前使用 Hibernate 并包含所有 hibernate 映射类,因此我正在考虑打开第一个数据库的第一个 session ,读取 hibernate Contrat 对象,在子元素中将 ids 设置为 null 并将该对象写入具有第二个 session 的目标数据库。应该会更快。
我为第二个用例编写了一个测试类,但该过程因以下异常而失败:
org.hibernate.HibernateException: Don't change the reference to a
collection with cascade="all-delete-orphan"
我认为当我将 ids 设置为 null 时,引用必须更改,但我不确定:我不明白更改 Collection 成员的字段如何更改 Collection 引用
请注意,如果我从配置中删除 DELETE_ORPHAN,则一切正常,所有对象及其依赖项都写入数据库中。 因此,我想使用速度更快的 hibernate 解决方案,但我必须保留 DELETE_ORPHAN 功能,因为应用程序当前使用此功能来确保从元素 Set 中删除的每个 MonElement 都将在数据库中删除。 我不需要此功能,但无法删除它。
此外,我需要将 MonElement id 设置为 null 才能生成新的,因为它们在第一个数据库中的 id 可能存在于目标数据库中。
这是我编写的代码,当我删除 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();
这比我自己管理查询、主/外键以及对象之间的依赖关系要快得多。
有人有办法摆脱这个异常吗? 或者也许我应该改变集合的状态。 事实上,我并不是想删除这个 Set 中的任何元素,我只是希望它们被视为新对象。
如果我找不到解决方案,我会做一些肮脏的事情:在我的新项目中复制所有 hibernate 实体对象,并删除新创建的 Contrat 中的 DELETE_ORPHAN 参数。 因此,应用程序将继续使用其映射,而我的新项目将使用我的特定映射。但我想避免这种情况。
谢谢
最佳答案
crizzis 已经编写了正确的解决方案作为对我的问题的评论。 我引用他的话:
I'd try wrapping the contrat.elements in a new collection (contrat.setElements(new HashSet<>(contrat.getElements())) before trying to persist the contract with the new session
效果很好。
关于java - 更新配置有删除孤儿 : can't save the parent object 的集合时出现 HibernateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55872208/