更新配置为 delete orphan 的集合时出现 HibernateException:无法保存父对象
HibernateException when updating a collection configured with delete orphan : can't save the parent object
我在一个 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" 对象并将它们写入另一个数据库。
我在两种解决方案之间犹豫不决:
- 使用jdbc查询第一个数据库并获取对象,然后将这些对象写入第二个数据库(注意顺序和不同的键)。会很长。
- 由于该项目当前使用 Hibernate 并包含所有休眠映射 classes,我正在考虑打开第一个数据库的第一个会话,读取休眠 Contrat 对象,将 ids 设置为空元素并使用第二个会话将对象写入目标数据库。应该会更快。
我为第二个用例编写了一个测试 class,但该过程失败并出现以下异常:
org.hibernate.HibernateException: Don't change the reference to a
collection with cascade="all-delete-orphan"
我认为当我将 id 设置为 null 时引用必须更改,但我不确定:我不明白更改集合成员的字段如何更改集合引用
请注意,如果我从配置中删除 DELETE_ORPHAN,一切正常,所有对象及其依赖项都写入数据库中。
所以我想使用更快的休眠解决方案,但我必须保留 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 的状态。
事实上,我并不是要删除这个 Set 的任何元素,我只是希望它们被视为新对象。
如果我找不到解决方案,我会做一些肮脏的事情:复制我新项目中的所有休眠实体对象并删除新创建的 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 项目上工作,我必须编写一个新模块才能将一些数据从一个数据库复制到另一个数据库(相同的表)。
我有一个包含多个字段和以下字段的实体 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" 对象并将它们写入另一个数据库。
我在两种解决方案之间犹豫不决:
- 使用jdbc查询第一个数据库并获取对象,然后将这些对象写入第二个数据库(注意顺序和不同的键)。会很长。
- 由于该项目当前使用 Hibernate 并包含所有休眠映射 classes,我正在考虑打开第一个数据库的第一个会话,读取休眠 Contrat 对象,将 ids 设置为空元素并使用第二个会话将对象写入目标数据库。应该会更快。
我为第二个用例编写了一个测试 class,但该过程失败并出现以下异常:
org.hibernate.HibernateException: Don't change the reference to a
collection with cascade="all-delete-orphan"
我认为当我将 id 设置为 null 时引用必须更改,但我不确定:我不明白更改集合成员的字段如何更改集合引用
请注意,如果我从配置中删除 DELETE_ORPHAN,一切正常,所有对象及其依赖项都写入数据库中。 所以我想使用更快的休眠解决方案,但我必须保留 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 的状态。 事实上,我并不是要删除这个 Set 的任何元素,我只是希望它们被视为新对象。
如果我找不到解决方案,我会做一些肮脏的事情:复制我新项目中的所有休眠实体对象并删除新创建的 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
效果很好。