There are a lot of articles about Hibernate associations in the internet and particularly on my blog. But JPA provides numerous combinations of associations, so it’s not strange that we still see new posts about this or that kind of association. Today I want to examine situation with the @JoinTable annotation and intermediary table. For the tutorial I’ll use MySQL, Hibernate as implementation of JPA and Maven.

Today’s example will be based on a simple situation – user role service. That means that I’m going to work with two entities: User, Role. Every user can has just one role. So in the database I need to create one table for the users, one table for the roles and the third one for the mapping of the roles to the users. The last table, as you understand, plays role of intermediary table.

JoinTable-Intermediary-table

Here is a code for the tables creation:

CREATE TABLE `roles` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `role` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE `users` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `login` varchar(20) NOT NULL,
  `password` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `user_roles` (
  `user_id` int(6) NOT NULL,
  `role_id` int(6) NOT NULL,
  KEY `user` (`user_id`),
  KEY `role` (`role_id`),
  CONSTRAINT `user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

After all tables were created I need to insert some roles into roles table:

INSERT INTO roles 
(role) 
VALUES 
('admin'),
('moderator');

The admin record will be with the id = 1, and the moderator record will be with the id = 2.
Now let’s move to a java code of the classes which will represent the tables:

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;

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

	@Id
	@GeneratedValue
	private Integer id;
	
	private String login;
	
	private String password;
	
	@OneToOne(cascade=CascadeType.ALL)
	@JoinTable(name="user_roles",
	joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
	inverseJoinColumns={@JoinColumn(name="role_id", referencedColumnName="id")})
	private Role role;
	
	public User(String login, String password) {
		this.login = login;
		this.password = password;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}
	
}

In this class you noticed that I applied a lot of annotations to the Role property. The @OneToOne annotation was used since users table is in “one to one” relationship with the user_roles table. The @JoinTable annotation indicates that we will interact with the intermediary table (user_roles) and further you can see settings of the relationship including mapping of columns.

The joinColumns attribute is responsible for the columns mapping of the owning side. The name attribute contains the column name of the intermediary table, the referencedColumnName attribute contains the primary key column name (in our case the primary key column of the user table is id) of the owning side.

The inverseJoinColumns attribute is responsible for the columns mapping of the inverse side. Here is everything is similar as in the explanation above, just with the one distinction – you need to apply this to the roles and user roles tables.
More information about associations you can read in the one of my previous posts.

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;

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

	@Id
	@GeneratedValue
	private Integer id;
	
	private String role;
	
	@OneToMany(cascade=CascadeType.ALL)
	@JoinTable(name="user_roles",
	joinColumns={@JoinColumn(name="role_id", referencedColumnName="id")},
	inverseJoinColumns={@JoinColumn(name="user_id", referencedColumnName="id")})
	private List<User> userList;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public List<User> getUserList() {
		return userList;
	}
	public void setUserList(List<User> userList) {
		this.userList = userList;
	}
	
}

In the Role entity, almost all annotations are the same as in the previous one. Pay your attention to @OneToMany annotation. Hence, appears property of collection type (private List userList).

Let’s see how this code can work:

public class DemoFirst {

	public static void main(String[] args) {

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		
		Role role = (Role) session.get(Role.class, 2);

		User user = new User("Fruzenshtein", "qwerty");
		user.setRole(role);
		
		session.save(user);
		
		session.getTransaction().commit();
		
		session.close();

	}
}

The result of the code execution is:

Hibernate: select role0_.id as id2_0_, role0_.role as role2_0_ from roles role0_ where role0_.id=?
Hibernate: insert into users (login, password) values (?, ?)
Hibernate: insert into user_roles (role_id, user_id) values (?, ?)

Summary

The @JoinTable annotation is a powerful feature of the Hibernate, it can be applicable to many situations to make your life easier. It can be used with two tables and with three, the last case I have demonstrated in this tutorial. You can find the sources of the application on my GitHub account.

About The Author

Mathematician, programmer, wrestler, last action hero... Java / Scala architect, trainer, entrepreneur, author of this blog

Close