问题
Unable to save child object reference.
Employee parent object contains the child employee_detail which also has a @ManyToOne defined to save Address object.
Table structure
EMPLOYEE
ID BIGINT(20) NOT NULL AUTO_INCREMENT
NAME VARCHAR(100) NOT NULL
EMPLOYEE_DETAIL
ID BIGINT(20) NOT NULL AUTO_INCREMENT
EMPLOYEE_ID BIGINT(20) NOT NULL
ADDRESS_ID BIGINT(20) NOT NULL
Entities
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List < EmployeeDetail > employeeDetails = new ArrayList < > ();
public void addEmployeeDetail(EmployeeDetail ed) {
employeeDetails.add(ed);
ed.setEmployee(this);
}
}
@Entity
@Table(name = "employee_detail")
public class EmployeeDetail {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@JoinColumn(name = "employee_id")
private Employee employee;
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@JoinColumn(name = "address_id")
private Address address;
}
In the REST Controller method:
public void saveEmployee(@RequestBody Employee employee)
{
EmployeeDetail employeeDetail = new EmployeeDetail();
employeeDetail.setEmployee(employee);
for(EmployeeDetail ed : employee.getEmployeeDetails())
{
Address address = addressService.findOne(ed.getAddress().getId());
employeeDetail.setAddress(address);
}
employee.addEmployeeDetail(employeeDetail);
//SAVE
employeeService.create(employee);
}
Exception:
nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.abc.Address
I am unable to save the Address details with the child table EmployeeDetail. What is wrong here?
回答1:
Apply CascadeType.MERGE too for Address entity as below
@ManyToOne(optional = false, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
@JoinColumn(name = "address_id")
private Address address;
and use merge() instead of persist to save your changes
EDIT
Yes you will have to apply the CascadeType.MERGE for EmployeeDetail too .. otherwise you will get the same exception if you have a detached EmployeeDetail instance in you network of objects starting from Employee.
There are couple of scenarios which you will need to consider.As explained below.
When you call persist() on your root entity all the entity association mapped with CascadeType.PERSIST are also passed to the persist() (transitive peristence) . Now if any of your entity in the object graph is detached persist() will be called for that entity too and you will get an exception for that entity.
In order to save your complete graph of objects which includes both detached and transient instances , mark your association with CascadeType.MERGE and call merge() on your root entity .. Now merge() operation will be cascaded to all the entity association mapped with CascadeType.MERGE. The behaviour of merge is that it will merge any detached entity being passed to it to the existing entity in the persistence context or if the entity is transient it will make it persistent.
So while trying to save you entity graph you need to choose whether to use persist() or merge() based on the info whether the entity graph you are going to save has only transient instances or it has both transient and detached instances.You will also have to consider the cascade type set on each association.
For your code .. i see the Address instance you are setting on the EmployeeDetail instance is detached as you are getting it from another already fetched EmplyeeDetail instance.
You can get more detail on below link
JPA EntityManager: Why use persist() over merge()?
You can also extend your persistence context by creating conversations if you dont want to work with detached instances.More on this below
http://www.thoughts-on-java.org/unsychronized-persistencecontext-implement-conversations-jpa/
回答2:
@Transacional
public void saveEmployee(@RequestBody Employee employee){
...
}
来源:https://stackoverflow.com/questions/38056926/exception-jpa-hibernate-detached-entity-passed-to-persist-while-saving-child-m