我有Academy实体:

@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;
}

以及Institute实体:
@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是子的(树状结构)。Institute具有Departments-但此时无所谓。我正在使用orphanRemoval = true删除所有Academy儿童(研究所等),当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..
}

当我使用application时,一切似乎都很好-当我删除与此相关的每个Academy和他的Institutes等等。。从数据库中删除(我正在使用Academy)。简言之,它表现为树状结构。但如果我试图用内存数据库(我在使用Department版本中的PostgreSQL 9.3来编写单元测试)来证明它:
@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());
}

与“Michigan”相关的指令仍在数据库中,其中“Michigan”是父指令,测试崩溃。这意味着我错了,而且在hsqldb数据库中,它们也没有被删除(但我检查了一下,发现2.3.2是空的)?或者,这只意味着当提交PostgreSQL时它们将被删除?因为测试方法需要Instututes,没有它测试就不会编译-但是,如何测试它呢?我被卡住了,因为在应用程序中看起来没问题,但在内存数据库的单元测试中,它并没有像我想的那样工作。如果有人帮我,我会很高兴的-提前谢谢你。
更新:问题是:Transaction在本地主机数据库上工作,我认为这是因为提交了事务,然后应用了级联删除。如何在单元测试中以不太复杂的方式做同样的事情-比如在测试结束之前提交事务(它触发级联删除),然后用另一个@Transactional获取orphanRemoval = trues?我在测试中尝试了privateInstitute方法,但它不起作用。

最佳答案

我认为问题可能在于测试中的事务处理方式与“普通”代码中的不同(这让我一次又一次感到困惑)。
让我们验证一下我对你的问题的理解是否正确:
使用mysql数据库运行应用程序时,一切正常。
但是当您对hsqldb cascade delete运行测试时,似乎失败了。
我认为这两种情况的区别在于处理事务,更重要的是从会话中刷新更改到数据库中的时间,即实际执行sql语句的时间。
要验证这一点,您可以激活sql日志记录来查看数据何时准确地存储在数据库中。我的期望是,在生产中,这种情况最晚发生在每个@Transactional方法的末尾,但是在测试中,由于测试中的@Transactional注释,所有事情都在单个事务中运行,并且不会发生刷新,或者至少不会在同一时间点。
为了模拟生产行为,您可以在通常事务结束的地方向Session.flush添加调用。

09-26 21:40