Hibernate - ManyToOne - Save - org.hibernate.TransientObjectException:
While I try to save top level entity (using JPA), do I need to get the ManyToOne mapped entity freshly from database and set it or cannot I just set Id (of manyToOne mapped entity and save top level entity? When do not get fresh entity i开发者_运维百科t throws: org.hibernate.TransientObjectException:
Table structures we are using:
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
}
(both classes have setter and getter methods for all fields and default constructor, constructor which takes primary key as argument) Now if I want to save Employee with departmentId (say 100), do I need to get the Department record first and then set it in employee?
Cannot I create instance of Department directly (by setting primary key(departmentId)) and set Department instance in Employee and save Employee? When I do this it is throwing org.hibernate.TransientObjectException.
Any suggestions on best practice to be followed for this?
Thank you in advance
If you want to associate your Employee
instance with new `Department instance, you can set an appropriate cascading behavior and let Hibernate take care of the whole thing:
class Employee {
...
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Department department;
}
Note that you do NOT want to use CascadeType.ALL
because deleting an employee should not delete a department.
If, OTOH, you want to associate your Employee
instance with existing `Department instance, your best approach is indeed to load it. You can use session.load() method for that purpose which will not hit the database.
An alternative solution is to use session.merge() on Employee
which (with cascading as specified above) will propagate to Department
. This can have side effects, though.
If you want to save the parent without saving each of the children, you need to map it something like (I can't remember the exact syntax)
@ManyToOne(CascadeType = Cascade.All)
Department department;
EDIT: I made the mistake of seeing it as parent-to-child instead of child-to-parent. Follow ChssPly76's example.
Thank you ChssPly76 and Wysawyg.
One of the solution could be: We will update Employee POJO as below
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;
(both department and departmentId will have setter and getter methods)
and Now here (please see that both department and departmentId mapped to same column (DEPARTMENT_ID) we use department only for fetching Department details and departmentId to insert or update Employee
But I am worried if it is a better approach.
精彩评论