我从事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个解决方案之间犹豫不决:
我为第二个用例编写了一个测试类,并且该过程失败,并带有以下异常:
org.hibernate.HibernateException: Don't change the reference to a
collection with cascade="all-delete-orphan"
我认为将id设置为null时引用必须更改,但是我不确定:我不知道更改Collection成员的字段如何可以更改Collection引用
请注意,如果我从配置中删除DELETE_ORPHAN,则一切正常,所有对象及其依赖项均写入数据库。 因此,我想使用更快的休眠解决方案,但我必须保留DELETE_ORPHAN功能,因为应用程序当前使用此功能来确保从元素集中删除的每个MonElement都将在数据库中删除。 我不需要此功能,但无法删除它。
另外,我需要将MonElement id设置为null以便生成新的id,因为它们在第一个数据库中的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的状态。 实际上,我并不是要删除此Set中的任何元素,我只是希望将它们视为新对象。
如果找不到解决方案,我将做一些肮脏的事情:在新项目中复制所有休眠实体对象,并在新创建的Contrat中删除DELETE_ORPHAN参数。 因此,应用程序将继续使用其映射,而我的新项目将使用我的特定映射。但我想避免这种情况。
谢谢
答案 0 :(得分:0)
crizzis 写了一个正确的解决方案,作为对我的问题的评论。 我引用他:
在尝试与新会话保持合同之前,我会尝试将contrat.elements包装在新集合中(contrat.setElements(new HashSet <>(contrat.getElements()))
效果很好。