Hibernate / JPA One-to-Many Mappings

Hibernate one to many mapping is made between two entities where the first entity can have a relation with multiple instances of the second entity but the second can be associated with only one instance of the first entity. It is a 1 to N relationship.

For example, in any company, an employee can register for multiple bank accounts but one bank account will be associated with one and only one employee. In this hibernate one to many mapping annotation examples, we will learn to make such mappings in the database using hibernate.

1. Design Overview

We should use one to many mapping to create 1..N relationship between entities or objects.

For example, as discussed above, we have to write two entities i.e. EmployeeEntity and AccountEntity such that multiple accounts can be associated with a single employee, but one single account can not be shared between two or more employees.

This problem can be solved in two different ways.

  1. One is to have a foreign key column in the ACCOUNT table i.e. EMPLOYEE_ID. This column will refer to the primary key of Employee table. This way no two accounts can be associated with multiple employees. Obviously, the account number needs to be unique for enforcing this restriction.
  2. The second approach is to have a link table. Let’s say the table name is EMPLOYEE_ACCOUNT. This table will have two columns i.e. EMP_ID that will be a foreign key referring to the primary key in EMPLOYEE table and similarly ACCOUNT_ID which will be a foreign key referring to the primary key of ACCOUNT table.

2. Using Foreign Key Association

We are designing a unidirectional relationship where when we delete an employee then account are deleted as well. But when we delete an account (one of many) then employee is unaffected.

2.1. Create Association

Let’s first see the schema design.

one-to-many-association-in-hiberate-using-foreign-key-7284046

Then we write the entity classes.

@Entity
@Table(name = "EMPLOYEE")
public class EmployeeEntity implements Serializable { 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private Integer employeeId;

  @OneToMany(cascade=CascadeType.ALL)
  @JoinColumn(name="EMPLOYEE_ID")
  private Set<AccountEntity> accounts;

  //Other fields, getters, setters are hidden for brevity
}
@Entity
@Table(name = "ACCOUNT")
public class AccountEntity implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private Integer accountId;

  //Other fields, getters, setters are hidden for brevity
}

2.2. Demo

Let’s test the relationship and monitor the CREATE queries.

create table Employee (
 ID integer generated by default as identity,
  EMAIL varchar(100) not null,
  FIRST_NAME varchar(100) not null,
  LAST_NAME varchar(100) not null,
  primary key (ID)
)

create table ACCOUNT (
 ID integer generated by default as identity,
  ACC_NUMBER varchar(100) not null,
  EMPLOYEE_ID integer,
  primary key (ID)
)

alter table if exists ACCOUNT 
       add constraint FKmyqrmihkv5isa3tjsj01x65sr 
       foreign key (EMPLOYEE_ID) 
       references Employee
AccountEntity account1 = new AccountEntity();
account1.setAccountNumber("Account detail 1");

AccountEntity account2 = new AccountEntity();
account2.setAccountNumber("Account detail 2");

AccountEntity account3 = new AccountEntity();
account3.setAccountNumber("Account detail 3");

//Add new Employee object
EmployeeEntity employee = new EmployeeEntity();
employee.setEmail("demo-user-first@mail.com");
employee.setFirstName("demo-one");
employee.setLastName("user-one");

Set<AccountEntity> accountList = new HashSet<AccountEntity>();
accountList.add(account1);
accountList.add(account2);
accountList.add(account3);

employee.setAccounts(accountList);

//Save Employee
session.persist(employee);

Program Output:

Hibernate: insert into Employee (ID, EMAIL, FIRST_NAME, LAST_NAME) values (default, ?, ?, ?)
Hibernate: insert into ACCOUNT (ID, ACC_NUMBER) values (default, ?)
Hibernate: insert into ACCOUNT (ID, ACC_NUMBER) values (default, ?)
Hibernate: insert into ACCOUNT (ID, ACC_NUMBER) values (default, ?)
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?

3. Using Link Table

This approach uses the @JoinTable annotation to create a link table that stores the associations between account and employee entities.

3.1. Create Association

Lets see how the database schema will look like:

one-to-many-association-in-hiberate-using-join-table-5973305
One To Many association in hibernate using a join table

On EmployeeEntity, we will add the @OneToMany annotation along with @JoinTable definition. This is the owning side.

@Entity
@Table(name = "EMPLOYEE")
public class EmployeeEntity implements Serializable { 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private Integer employeeId;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "EMPLOYEE_ACCOUNT", 
  joinColumns = {@JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "ID")},
  inverseJoinColumns = {@JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")})
private Set<AccountEntity> accounts;

  //Other fields, getters, setters are hidden for brevity
}

If we want to create a bi-directional relationship then we need to use @ManyToOne association on the child side.

@Entity
@Table(name = "EMPLOYEE")
public class EmployeeEntity implements Serializable { 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private Integer employeeId;

@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "EMPLOYEE_ACCOUNT", 
  joinColumns = {@JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "ID")},
  inverseJoinColumns = {@JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")})
private Set<AccountEntity> accounts;

  //Other fields, getters, setters are hidden for brevity
}

@Entity
@Table(name = "ACCOUNT")
public class AccountEntity implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private Integer accountId;

  @ManyToOne
  private EmployeeEntity employee;

  //Other fields, getters, setters are hidden for brevity
}

3.2. Demo

Now, it’s time to test the code. I have written the following code to test the above entities.

AccountEntity account1 = new AccountEntity();
account1.setAccountNumber("123-345-65454");

AccountEntity account2 = new AccountEntity();
account2.setAccountNumber("123-345-6542222");

//Add new Employee object
EmployeeEntity emp = new EmployeeEntity();
emp.setEmail("demo-user@mail.com");
emp.setFirstName("demo");
emp.setLastName("user");

Set<AccountEntity> accounts = new HashSet<>();
accounts.add(account1);
accounts.add(account2);

emp.setAccounts(accounts);

//Save Employee
session.persist(emp);

Program Output:

Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME, ID) values (?, ?, ?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, ID) values (?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, ID) values (?, ?)
Hibernate: insert into EMPLOYEE_ACCOUNT (EMPLOYEE_ID, ACCOUNT_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_ACCOUNT (EMPLOYEE_ID, ACCOUNT_ID) values (?, ?)

In this hibernate @OneToMany mapping annotation example using list, we learned to create 1..N relationships between two entities using foreign key association and join table techniques.

Happy Learning !!

Sourcecode on Github

Leave a Reply

47 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.