当我尝试保存顶级实体(使用JPA)时,我是否需要从数据库中新获取ManyToOne映射实体并设置它或者我不能设置Id(manyToOne映射实体并保存顶级实体? 如果没有得到新的实体,它会抛出:org.hibernate.TransientObjectException:
我们正在使用的表结构:
DEPARTMENT(DEPARTMENT_ID BIGINT, NAME VARCHAR(128))
EMPLOYEE(EMPLOYEE_ID BIGINT, NAME VARCHAR(128), DEPARTMENT_ID BIGINT)
Entities:
class Department
{
@Id
Long departmentId;
String name;
@Version
Long versionNumber;
}
class Employee
{
@Id
Long employeeId;
String name;
@ManyToOne
Department department;
@Version
Long versionNumber
}
(两个类都有所有字段的setter和getter方法以及默认构造函数,构造函数将主键作为参数) 现在,如果我想用departmentId(比如100)保存员工,我是否需要先获取部门记录然后在员工中设置?
我不能直接创建Department实例(通过设置主键(departmentId))并在Employee中设置Department实例并保存Employee? 当我这样做时,它会抛出org.hibernate.TransientObjectException。
有关最佳做法的建议吗?
提前谢谢
答案 0 :(得分:7)
如果您想将Employee
实例与新`部门实例相关联,可以设置an appropriate cascading behavior并让Hibernate处理整个事情:
class Employee {
...
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Department department;
}
请注意,您 NOT 想要使用CascadeType.ALL
,因为删除员工不应删除部门。
如果,OTOH,您想要将Employee
实例与现有`部门实例相关联,那么您的最佳方法确实是加载它。您可以使用session.load()方法,不会访问数据库。
另一种解决方案是在Employee
上使用session.merge()(如上所述级联)将传播到Department
。但是,这可能会产生副作用。
答案 1 :(得分:1)
如果你想保存父节点而不保存每个子节点,你需要映射它(我不记得确切的语法)
@ManyToOne(CascadeType = Cascade.All)
Department department;
编辑:我错误地认为它是父母对孩子而不是孩子对父母。按照ChssPly76的例子。
答案 2 :(得分:1)
谢谢ChssPly76和Wysawyg。
其中一个解决方案可能是: 我们将更新员工POJO,如下所示
ManyToOne(fetch=FetchType.EAGER)
@**JoinColumn**(name = "DEPARTMENT_ID", referencedColumnName = "DEPARTMENT_ID", **insertable=false, updatable=false**)
private Department department;
@Column(name = "department_id")
private Long departmentId;
(department和departmentId都有setter和getter方法)
现在在这里(请注意,department和departmentId都映射到同一列(DEPARTMENT_ID) 我们仅使用部门来获取部门详细信息 和departmentId插入或更新员工
但我担心这是否是一种更好的方法。