orphanRemoval 在 PostgreSQL 中工作但在 hsqldb 中不工作
orphanRemoval working in PostgreSQL but not in hsqldb
我有 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
是 parent,Institute
是孩子(tree-like 结构)。 Institute
有 Department
s - 但此刻并不重要。当 Academy
被移除时,我正在使用 orphanRemoval = true
移除所有 Academy
个子项(学院等...)(class 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
每个 Institute
与此 Academy
和他的 Department
等相关.. 从数据库中删除(我正在使用 PostgreSQL 9.3
)。简而言之 - 它表现为 tree-like 结构。但是如果我尝试用 in-memory 数据库编写单元测试(我在 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());
}
与 "Michigan" 相关的研究所仍然在数据库中,"Michigan" 为 parent 并且测试崩溃。这意味着我错了,在 PostgreSQL
数据库中它们也没有被删除(但我检查它并且 Instututes
是空的)?或者,这仅意味着它们将在 Transaction
提交时被删除?因为测试方法需要 @Transactional
,没有它测试将无法编译 - 但是,如何测试呢?我被卡住了,因为在应用程序中它看起来不错,但是在 in-memory 数据库的单元测试中它不能像我认为的那样工作。如果有人帮助我,我将非常高兴 - 在此先感谢您。
更新: 问题是:orphanRemoval = true
在本地主机数据库上工作,在我看来,因为提交了事务,然后应用了级联删除。我怎样才能在单元测试中以不太复杂的方式做同样的事情——比如在测试结束前提交事务(触发级联删除),然后用另一个 Transaction
得到 Institute
s?我在测试中尝试了私有 @Transactional
方法,但它不起作用。
请注意spring APP 不会削减@Transactional 的私有方法。尝试制作测试实用程序方法 public,然后再次调用。希望有用!
我认为问题可能在于测试中的事务处理方式与 "normal" 代码中的处理方式不同(这让我一遍又一遍地感到困惑)。
让我们验证一下我是否正确理解你的问题:
当您 运行 使用 mysql 数据库的应用程序时,一切正常。
但是当你 运行 你对 hsqldb 级联删除的测试似乎失败了。
我认为这两种情况的区别在于事务的处理,更重要的是更改从会话刷新到数据库的时间,即 sql 语句实际执行。
要验证这一点,您可以激活 sql 日志记录以查看您的数据何时准确存储在数据库中。我的期望是,在生产中,这最晚发生在每个 @Transactional 方法的末尾,但在测试单个事务中的所有 运行s 由于测试中的 @Transactional 注释并且没有刷新发生,或者在至少不是在同一时间点。
为了模拟生产行为,您可以在通常交易结束的地方添加对 Session.flush
的调用。
我有 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
是 parent,Institute
是孩子(tree-like 结构)。 Institute
有 Department
s - 但此刻并不重要。当 Academy
被移除时,我正在使用 orphanRemoval = true
移除所有 Academy
个子项(学院等...)(class 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
每个 Institute
与此 Academy
和他的 Department
等相关.. 从数据库中删除(我正在使用 PostgreSQL 9.3
)。简而言之 - 它表现为 tree-like 结构。但是如果我尝试用 in-memory 数据库编写单元测试(我在 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());
}
与 "Michigan" 相关的研究所仍然在数据库中,"Michigan" 为 parent 并且测试崩溃。这意味着我错了,在 PostgreSQL
数据库中它们也没有被删除(但我检查它并且 Instututes
是空的)?或者,这仅意味着它们将在 Transaction
提交时被删除?因为测试方法需要 @Transactional
,没有它测试将无法编译 - 但是,如何测试呢?我被卡住了,因为在应用程序中它看起来不错,但是在 in-memory 数据库的单元测试中它不能像我认为的那样工作。如果有人帮助我,我将非常高兴 - 在此先感谢您。
更新: 问题是:orphanRemoval = true
在本地主机数据库上工作,在我看来,因为提交了事务,然后应用了级联删除。我怎样才能在单元测试中以不太复杂的方式做同样的事情——比如在测试结束前提交事务(触发级联删除),然后用另一个 Transaction
得到 Institute
s?我在测试中尝试了私有 @Transactional
方法,但它不起作用。
请注意spring APP 不会削减@Transactional 的私有方法。尝试制作测试实用程序方法 public,然后再次调用。希望有用!
我认为问题可能在于测试中的事务处理方式与 "normal" 代码中的处理方式不同(这让我一遍又一遍地感到困惑)。
让我们验证一下我是否正确理解你的问题:
当您 运行 使用 mysql 数据库的应用程序时,一切正常。
但是当你 运行 你对 hsqldb 级联删除的测试似乎失败了。
我认为这两种情况的区别在于事务的处理,更重要的是更改从会话刷新到数据库的时间,即 sql 语句实际执行。
要验证这一点,您可以激活 sql 日志记录以查看您的数据何时准确存储在数据库中。我的期望是,在生产中,这最晚发生在每个 @Transactional 方法的末尾,但在测试单个事务中的所有 运行s 由于测试中的 @Transactional 注释并且没有刷新发生,或者在至少不是在同一时间点。
为了模拟生产行为,您可以在通常交易结束的地方添加对 Session.flush
的调用。