Many to Many
layout: default
title: @ManyToMany
Relational databases model many-to-many relationship through a join table.
-
If the join table contains no extra data beyond foreign keys, you should not build a separate entity for it (this is called a Virtual Join Table).
-
However, if the join table contains additional data, then you should create an entity to represent it. We will do that later.
In a many-to-many, either side of the relationship can be chosen as the owning side.
- In the owning entity, annotate a collection typed field (e.g. List, Set, etc.) with
@ManyToManyand@JoinTable.
@Entity
public class Actor {
// ...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToMany
@JoinTable(name="film_actor",
joinColumns=@JoinColumn(name="actor_id"),
inverseJoinColumns=@JoinColumn(name="film_id")
)
private List<Film> films;
// ...
}
@JoinTable has three elements:
-
name- the name of the actual SQL table functioning as a join table. (See film_actor below.) -
joinColumns- is assigned a@JoinColumncontaining the column name (actor_id) in the join table that matches the primary key (id) in the owning entity (Actor). -
inverseJoinColumns- a@JoinColumnthat identifies the column in the join table (film_id) that matches the primary key (id) in the non-owning entity (Film).
-- actor
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| first_name | varchar(45) | NO | | NULL | |
| last_name | varchar(45) | NO | MUL | NULL | |
+------------+------------------+------+-----+---------+----------------+
-- film_actor (the join table)
+----------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+-------+
| actor_id | int(10) unsigned | NO | PRI | NULL | |
| film_id | int(10) unsigned | NO | PRI | NULL | |
+----------+------------------+------+-----+---------+-------+
-- film
+------------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-----------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | MUL | NULL | |
| description | text | YES | | NULL | |
+------------------+------------------------+------+-----+---------+----------------+
In the non-owning entity (Film) of a bi-directional relationship, add the @ManyToMany annotation above the collection typed field that references the owning entity (Actor).
- Use the
mappedByelement to specify the defining field in the owning entity.
@Entity
public class Film {
// ...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToMany(mappedBy="films")
private List<Actor> actors;
// ...
}
Digging Deeper¶

Drill¶
In Actor add a field of type
List<Film>namedfilms. Annotate it with@ManyToMany. Let’s choose Actor as the owning side of this relationship, so it will define the@JoinTableannotation as well.Since Film is the non-owning side, add a
mappedByelement within its@ManyToMany. As in the example, the value of themappedByshould match the name of the corresponding field in Actor.Generate get and set methods for your new fields. Then, update your JUnit test for Film to verify your new associations work. Also create a JUnit test to ensure that the Actor entity's fields are mapped correctly, and that actors do indeed have films.