eatSleepCode
eatSleepCode

Reputation: 4637

Unnecessary updates in @OneToMany

I have model object as follows

Employee.java
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
    @Id
    @SequenceGenerator(name = "emp_seq", sequenceName = "seq_employee")
    @GeneratedValue(generator = "emp_seq")
    @Column(name = "EMPLOYEE_ID")
    private Integer employeeId;
    @Column(name = "EMPLOYEE_NAME")
    private String employeeName;
}

Department.java
@Entity
@Table(name = "DEPARTMENT")
public class Department {
    @Id
    @Column(name = "DEPARTMENT_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer departmentId;
    @Column(name = "DEPARTMENT_NAME")
    private String departmentName;
    @Column(name = "LOCATION")
    private String location;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "DEPARTMENT_ID")
    private List<Employee> employees = new ArrayList<>();
}

while saving this it is generating two extra update statements.

Test class

    Employee e1 = new Employee();
    e1.setEmployeeName("Employee-1");

    Employee e2 = new Employee();
    e2.setEmployeeName("Employee-2");

    Department d = new Department();
    d.setDepartmentName("Test");
    d.setLocation("Test");

    d.getEmployees().add(e1);
    d.getEmployees().add(e2);
    em.getTransaction().begin();
    em.persist(d);
    em.getTransaction().commit();

on committing the following statements are generated...

Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?

my question here is why 2 extra update(marked by *) statements are needed?

Upvotes: 0

Views: 295

Answers (3)

Mike Argyriou
Mike Argyriou

Reputation: 1310

Due to the @OneToMany @JoinColumn(name = "DEPARTMENT_ID") that annotates the attribute Department.employees the table EMPLOYEE has a foreign key to the table DEPARTMENT. When you persiste the new department with the two employees a new row is inserted into the table DEPARTMENT and two rows are inserted into the table EMPLOYEE but the column DEPARTMENT_ID is null. Then two updates are executed to set this column and relate the EMPLOYEE rows with the DEPARTMENT row.

The question is why this is not done in one step, i.e. instead of executing the following:

Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?

the following should be executed:

Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID, DEPARTMENT_ID) values (?, ?, ?)

Upvotes: 0

Kratul
Kratul

Reputation: 158

When you add Employees to a Department, employees must have a Department ID so that's the reason why Hibernate do an extra update.

If you want to avoid it you can create first the department, and then the employees adding manually Department id

Upvotes: 0

Andres
Andres

Reputation: 10725

That's the order on which Hibernate does the operations normally. Take a look at this

https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/event/internal/AbstractFlushingEventListener.html#performExecutions%28org.hibernate.event.spi.EventSource%29

According to this documentation:

Execute all SQL (and second-level cache updates) in a special order so that foreign-key constraints cannot be violated:

Upvotes: 1

Related Questions