In which case do you use the JPA @JoinTable
annotation?
Advertisement
Answer
EDIT 2017-04-29: As pointed to by some of the commenters, the JoinTable
example does not need the mappedBy
annotation attribute. In fact, recent versions of Hibernate refuse to start up by printing the following error:
org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn
Let’s pretend that you have an entity named Project
and another entity named Task
and each project can have many tasks.
You can design the database schema for this scenario in two ways.
The first solution is to create a table named Project
and another table named Task
and add a foreign key column to the task table named project_id
:
Project Task ------- ---- id id name name project_id
This way, it will be possible to determine the project for each row in the task table. If you use this approach, in your entity classes you won’t need a join table:
@Entity public class Project { @OneToMany(mappedBy = "project") private Collection<Task> tasks; } @Entity public class Task { @ManyToOne private Project project; }
The other solution is to use a third table, e.g. Project_Tasks
, and store the relationship between projects and tasks in that table:
Project Task Project_Tasks ------- ---- ------------- id id project_id name name task_id
The Project_Tasks
table is called a “Join Table”. To implement this second solution in JPA you need to use the @JoinTable
annotation. For example, in order to implement a uni-directional one-to-many association, we can define our entities as such:
Project
entity:
@Entity public class Project { @Id @GeneratedValue private Long pid; private String name; @JoinTable @OneToMany private List<Task> tasks; public Long getPid() { return pid; } public void setPid(Long pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Task> getTasks() { return tasks; } public void setTasks(List<Task> tasks) { this.tasks = tasks; } }
Task
entity:
@Entity public class Task { @Id @GeneratedValue private Long tid; private String name; public Long getTid() { return tid; } public void setTid(Long tid) { this.tid = tid; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
This will create the following database structure:
The @JoinTable
annotation also lets you customize various aspects of the join table. For example, had we annotated the tasks
property like this:
@JoinTable( name = "MY_JT", joinColumns = @JoinColumn( name = "PROJ_ID", referencedColumnName = "PID" ), inverseJoinColumns = @JoinColumn( name = "TASK_ID", referencedColumnName = "TID" ) ) @OneToMany private List<Task> tasks;
The resulting database would have become:
Finally, if you want to create a schema for a many-to-many association, using a join table is the only available solution.