我有学院
实体:
@Entity
@Table(name = "academy")
public class Academy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String address;
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "parent")
private List<Institute> institutes;
public Academy() {}
public Academy(String name, String address, List<Institute> institutes) {
this.name = name;
this.address = address;
this.institutes = institutes;
}
和研究所
实体:
@Entity
@Table(name = "institute")
public class Institute {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String name;
@Column(name = "building_code")
private String buildingCode;
@ManyToOne(optional = false)
private Academy parent;
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "parent")
private List<Department> departments;
public Institute() {}
public Institute(String name, String buildingCode, Academy parent, List<Department> departments) {
this.name = name;
this.buildingCode = buildingCode;
this.parent = parent;
this.departments = departments;
parent.getInstitutes().add(this);
}
这个想法是,Academy
是父级,Institute
是子级(树状结构)。 学院
有部门
- 但目前并不重要。当删除 Academy
时(类 UnitServiceImpl. java
):
@Override
@Transactional
public String remove(String whatIsRemoved, Long id) {
if (whatIsRemoved.equals("academy")){
Academy academy = getAcademyById(id);
academy.getInstitutes().clear();
getCurrentSession().delete(academy);
}
else if (whatIsRemoved.equals("institute")){
Institute institute = getInstituteById(id);
institute.getParent().getInstitutes().remove(institute);
}
//other if's etc..
}
当我使用应用程序时,一切似乎都正常 - 当我删除Academy
时,与该Academy
及其相关的每个Institute
部门
等已从数据库中删除(我使用的是PostgreSQL 9.3
)。简而言之 - 它表现为树状结构。但是,如果我尝试使用内存数据库编写单元测试(我在 2.3.2
版本中使用 hsqldb
),这应该证明这一点:
@Test
@Transactional
public void test_WhenAcademyWasRemoved_InstitutesAlsoShouldBeRemoved() throws Exception {
UnitServiceImpl service = new UnitServiceImpl();
service.setSessionFactory(sessionFactory);
AcademyDTO michigan = new AcademyDTO(null, "Michigan", "test");
service.saveAcademy(michigan);
service.saveInstitute(new InstituteDTO(null, "IT", "D", getAcademyIdByName(service, "Michigan"), null));
service.remove("academy", getAcademyIdByName(service, "Michigan"));
List<Institute> institutes = (List<Institute>)sessionFactory.getCurrentSession().createCriteria(Institute.class).list();
assertEquals(0, institutes.size());
}
与“密歇根”相关的机构仍在数据库中,以“密歇根”为父级,并且测试崩溃。这意味着我错了,在 PostgreSQL
数据库中它们也没有被删除(但我检查它并且 Instututes
为空)?或者,这仅意味着当提交 Transaction
时它们将被删除?因为测试方法需要是@Transactional
,没有它测试将无法编译 - 但是,如何测试它呢?我被困住了,因为在应用程序中它看起来不错,但在内存数据库的单元测试中它不能像我认为的那样工作。如果有人帮助我,我将非常高兴 - 预先感谢您。
更新:问题是:orphanRemoval = true
在本地主机数据库上工作,在我看来,因为事务已提交,然后应用级联删除。我如何在单元测试中以不太复杂的方式做同样的事情 - 比如在测试结束之前提交事务(触发级联删除),然后使用另一个 Transaction
获取 Institute
?我在测试中尝试了私有(private) @Transactional
方法,但它不起作用。
最佳答案
我认为问题可能在于测试中的事务处理方式与“正常”代码中的处理方式不同(这让我一次又一次感到困惑)。
让我们验证一下我是否正确理解您的问题:
当您使用 mysql 数据库运行应用程序时,一切正常。
但是当您针对 hsqldb 级联删除运行测试时似乎失败了。
我认为这两种场景之间的区别在于事务的处理,更重要的是更改从 session 刷新到数据库的时间,即 sql 语句实际执行的时间。
要验证这一点,您可以激活 SQL 日志记录以查看数据何时存储在数据库中。我的期望是,在生产中,这种情况最晚会在每个 @Transactional 方法结束时发生,但在测试中,由于测试上的 @Transactional 注释,所有内容都在单个事务中运行,并且不会发生刷新,或者至少不会同时发生时间点。
为了模拟生产行为,您可以在事务通常结束的地方添加对 Session.flush
的调用。
关于java - orphanRemoval 在 PostgreSQL 中工作但在 hsqldb 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30156908/