我试图理解为什么persist()的行为在ManyToOne上是不同的,在第一种情况下,持久化新实体,其次,修改该实体。我的测试设置有Employee,它有一个带有Department的单向ManyToOne;部门与员工之间没有任何关系。对于测试,我在Employee的Department字段中没有任何级联注释。
我发现在创建一个Employee时,我必须调用em.persist(dept),否则dept实例不会被持久化,我会得到一个异常。所以,我正在调用em.persist(dept),以便dept实体被持久化。我的下一个测试是提交,并启动一个新事务,使用em.find()检索员工实体,修改dept.name,然后保留该员工。我发现,虽然在Employee的Department字段中没有任何级联注释,但是部门的更改仍然存在。
为什么是这样?为什么部门的更改会持续存在(通过em.persist(emp))到数据库而没有任何级联,但是当员工第一次持久化时,部门的创建不会持久存在?我错过了什么?顺便说一下,在测试结束时,部门名称(FURTHER MATHS)的更改仍然存在。谢谢。
编辑我刚刚读到“你可以在一个已经持久的实例上调用这个方法(persist()),并且没有任何事情发生在https://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate。我认为这意味着在changeDept()中,我在find()之后调用persist()是多余的,所以我删除了它,结果是一样的。所以这让我想到除了许多误解之外,其中一个可能是我对persist()的理解,以及它如何与实体(及其相关实体)的状态变化传播到db有关或不相关。但是,仍然没有Department上的cascadeType注释。
EDIT2我想我到了某个地方。我添加了一个新方法,它创建了一个新的部门(“ENGLISH”),像以前一样使用find()检索员工,将员工的部门设置为新部门,然后提交。我得到(幸运的是,正如预期的那样)一个例外:
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
如果我在部门字段上放置PERSIST cascadeType,则不会发生此异常。所以显而易见的是,持久性适用于坚持新实体;它不适用于将更改传播到现有实体。问题仍然存在,是默认行为(即没有指定任何cascadeType)将更改传播到相关实体)?我想它一定是。
@Entity
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private double salary;
@ManyToOne
private Department department;
...
}
部门:
@Entity
public class Department {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
..
}
方法:
static void setupData() {
try {
em.getTransaction().begin();
Department dept = new Department();
dept.setName("MATHS");
...
Employee emp2 = new Employee("Darth Vader", 10003, dept);
em.persist(emp2);
em.persist(dept); //needed without cascadeType=PERSIST on Department
em.getTransaction().commit();
} catch (Exception e) {
logger.error("oops: " + e);
e.printStackTrace();
em.getTransaction().rollback();
}
}
static void changeDept() {
try {
em.clear();
em.getTransaction().begin();
Employee emp1 = em.find(Employee.class, 2);
logger.info("emp1:" + emp1);
Department dept = emp1.getDepartment();
dept.setName("FURTHER MATHS");
em.persist(emp1);
em.getTransaction().commit();
} catch (Exception e) {
logger.error("oops: " + e);
e.printStackTrace();
em.getTransaction().rollback();
}
}