Skip to main content

Hibernate Many to Many relational Mapping

Points To Remember

Suppose we have two domains/ entities User and Role and we want to create a many to many relationship between them them, then we can do it like following in hibernate.

Many to Many relationship between two Entities.

User.java
Create a User class as following
package com.ekiras.domain;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Long id;

@Column(name="email")
private String email;

@Column(name="password")
private String password;

@Column(name="enabled")
private boolean enabled;

@ManyToMany(cascade=CascadeType.ALL)
private Collection<Role> roles = new ArrayList<Role>();

// GETTERS and SETTERS

Role.java
Create the Role class as follows
package com.ekiras.domain;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="role")
public class Role {

public Role(){}
public Role(String authority){
this.authority=authority;
}

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Long id;

@Column(name="authority")
private String authority;

@ManyToMany(mappedBy="roles")
private Collection<User> users = new ArrayList<User>();

// GETTERS and SETTERS

}

What we have done here is

  • We have created the User class and taken a Collection of Roles in User class, as a User can have multiple roles. This class will do the mapping for the User and Role relationship.
  • We have then created a class Role and taken a Collection of User, since a Role can be assigned to multiple users.
  • We have used property mappedBy="roles" in Role class, since our mapping has already been done by the users field of the User class.
  • If we do not specify mappedBy property in either of the class, then there will be two tables, one by User class and one by Role class.
  • In our case the extra table that will be created will be user_role if want to create the table other way round, then we have to set property mappedBy="users" in User class and remover mappedBy property from Role class.
  • The property cascade=CascadeType.ALL is used to save nested objects, this way you do not need to save the nested objects separately. If you did not set this property then you will have to first save Role objects and then save User object or else it would give the following expection.
    org.hibernate.TransientPropertyValueException: object references an unsaved transient 

TestController.java
Create the TestController class as follows
package com.ekiras.controller;

import java.util.ArrayList;
import java.util.Collection;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ekiras.domain.Role;
import com.ekiras.domain.User;

@Controller
@RequestMapping(value={"","/**"})
public class TestController {

@Autowired
protected SessionFactory sessionFactory;

@RequestMapping(value="/test")
public String test(){

Role role1 = new Role("ROLE_ADMIN");
Role role2 = new Role("ROLE_USER");

Collection<Role> roles = new ArrayList<Role>();
roles.add(role1);
roles.add(role2);

User user = new User();
user.setEmail("ekansh@ekiras.com");
user.setPassword("password");
user.setEnabled(true);
user.setRoles(roles);


Session session = sessionFactory.openSession();
session.beginTransaction();
boolean result = (Long)session.save(user)!=0;

session.getTransaction().commit();
session.close();

System.out.println("User object saved = " + result);


return "/home";
}

}

This will save the user with two roles, the following image shows the data created by the test controller.



Comments