0

How do I store the same table row in the database for two entities that contain the same object? The following illustrates my invalid attempt.

@Entity
public class Employee 
  {
  @ManyToOne(cascade=CascadeType.ALL)
  private Department department;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String name;
  ...
  <Getters and setters for all members here>
  ...
  }

@Entity
public class Department 
  {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String name;
  @OneToMany(mappedBy="department")
  private Collection<Employee> employees;
  ...
  <Getters and setters for all members here>
  ...
  }

In the Servlet I try the following:

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("Anna");
employee2.setDepartment(department);
...
em.persist(employee1);
em.persist(employee2);

When I do this I get an error when employee2 is persisted that the primary key for department is already in the database as it tries to add the same department for a second time.

How do I achieve both employees pointing to the same row in the database.

Do I have to work from the inverse side by adding the employees to the department to achieve this?

I feel like I am missing something fundamental here.

JJW
  • 1
  • 2

2 Answers2

2

I think you need to add join column relationship(with @JoinColumn) in Employee class with department id if it is foreign key. Refer this link for more information.

Community
  • 1
  • 1
ypp
  • 144
  • 2
  • 8
  • But the missing **@JoinColumn** annotation cannot be the problem in this case because the persistence provider will use the default, i.e. **DEPARTMENT_ID**, where **department** being the attribute in the owning entity (**Employee**) and **id** is the primary key in the target entity (**Department**). – ujulu Mar 24 '16 at 07:40
  • By default JoinTable will be used available only in case of unidirectional relationship. Not in case of bidirectional relationship. Refer this [link](http://stackoverflow.com/questions/8572554/onetomany-what-are-the-differences-between-join-table-and-foreign-key) – ypp Mar 24 '16 at 08:25
  • I haven't meant **JoinTable** but **JoinColumn**. You can look at JPA 2.0 Specification section **2.10.2** for detailed explanation. – ujulu Mar 24 '16 at 10:12
0

Upon testing some examples I determined at least two ways to achieve this.

The first way, that seems the most straightforward, is not to use cascading (remove cascade=CascadeType.ALL from the relationship) and insert the department first.

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
Employee employee2=new Employee();
employee2.setName("Anna");
...
em.persist(department);
employee1.setDepartment(department);
em.persist(employee1);
employee2.setDepartment(department);
em.persist(employee2);

This works because the ManyToOne relationship in Employee stores a foreign key to the Department table. The department has to be persisted first or the foreign key won't exist when then the employees are added.

The other way to achieve this is to put the cascading on the inverse side.

In the Department class change

@OneToMany(mappedby="department")

to

@OneToMany(mappedby="department",cascade=CascadeType.ALL)

Then the following will work:

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("Anna");
employee2.setDepartment(department);
...
department.addEmployee(employee1);
department.addEmployee(employee2);
em.persist(department);

Both of these will result in two tables in the database

department
ID  NAME
3    HR

employee
ID  NAME DEPARTMENT_ID
20   Bob     3
21   Anna    3

Note: The exact ID numbers will probably be different since they are auto generated here.

And yet another way would be to make the Department the owner and the Employee the inverse relationship and perform something similar.

JJW
  • 1
  • 2