Introductie
During this part of the training we will instruct using JPA
-
OneToMany
-
ManyToOne
-
ManyToMany
Definitions
-
Unidirectional vs bidirectional
-
OneToMany
-
ManyToOne
-
ManyToMany
@OneToOne
Unidirectional
Suppose an Employee always has a single address and we have to model it in jpa
Then the following JAVA code (BLUE) will be created by you, the programmer, and Database (RED) will be created then automagically by JPA

So we create the entity Addresss
package nl.programit.people.domain;
... imports omitted
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String street;
private int number;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
Example code
@Entity
public class Employee {
@Id
private long id;
// fails with the exception that JPA does not know what type of column to create for Address? Clear??
private Address address;
public void setAddress(Address address) {
this.address = address;
}
}
Fix the problem above with the @OneToOne annotation so JPA knows that it has to make a mapping to another table called a relationship / foreign key
@Entity
public class Employee {
@Id
private long id;
@OneToOne
private Address address;
public void setAddress(Address address) {
this.address = address;
}
}
Using the least work principe that is all we have to do to create the relationship
-
it creates the table Address
-
it creates an address_id column in the table Person
Now we have create a so called unidirectional relationship which means we can only traverse from the Person to the Address
The address table / entity does not have any clue to which person it belongs!!!
Bidirectional
Suppose we want to tell JPA also to wire the direction from Address to Person Than we have to add this to the JPA Address entity
// fetch = do we get all addressen when fetching a Person or do we fetch them when we "dive" into them ...
/// mappedBy = the other / owning side his property (in this case address since that is the owning side of Person)
@OneToOne(fetch=FetchType.LAZY, mappedBy="address")
private Person person;
// add getters and setters
Question: what happens to the tables in the people app?
Answer … after a minute of discussing? Nothing … why ? :-)
Since if jpa has an adress entity he can found the person by finding a person with an adress_id which is the samen as the id of this address instance.
@OneToMany
Unidirectional
Suppose a person has many phones AND a phone belongs to one person

We than use the @OneToMany annotation
@OneToMany
private Set<Phone> phones = new HashSet<>();
public void addPhone(Phone phone) {
this.phones.add(phone);
}
JPA then creates a person_phones table? Why ?
Since the entity Phone does not know that he is even linked to a Person hence JPA creates a so called link table (Dutch: koppel tabel)
Bidirectional
Suppose we want to be able to get the person which own the phone
Add the mappedBy property to the @OneToMany annotation on the owning side
The mappedBy is ALWAYS the type of the Set we are dealing with. Hence in this case it is the Phone class - which has the @ManyToOne - annotation. Just pick the name of the variable and you are done … for now :-)
public class Person {
private String name;
...
...
@OneToMany(mappedBy="person") // person is the private Person instance var in the phone class
private Set<Phone> phones = new HashSet<>();
public Set<Phone> getPhones() {
return this.phones;
}
public void addPhone(Phone phone) {
this.phones.add(phone);
}
}
public class Phone {
private String phoneNumber;
...
...
@ManyToOne
private Person person;
}
@ManyToMany
Introducing jointable
In a ManyToMany relationship we have a so-called many-to-many relationship between two classes.
e.g. A Person can have many hobbies and a hobby can have many Person(s).
JPA will create a so called join-table / link-table (Dutch: koppeltabel) to link the relationship between the two
Introducing Cascading
During this ManyToMany relationship part we also are talking about Cascading. In this case, cascading means … what should we do when we delete a Person? Should we also delete his phones in the relationship?
What you should know is that the @ManyToMany annotation has a 'cascade' attribute which you can set.
-
ALL
-
PERSIST
-
MERGE
-
REMOVE
-
REFRESH
-
DETACH
You are telling with this annotation what JPA should do on the action. So if we say … cascade=CascadeType.REMOVE on the Person class on the Hobbies set than removing a Person will also remove the links from the linktable after deletion
Unidirectional
Suppose a person has many hobbies and a hobby can belong to multiple persons

@ManyToMany(cascade=CascadeType.ALL)
private Set<Hobby> hobbies = new HashSet<>();
public void addHobby(Hobby h) {
this.hobbies.add(h);
h.getPeople().add(this);
}
The machine creates a join table (in this case hobbies_people)
Bidirectional
Suppose want to see al people who like running
@ManyToMany(mappedBy="people", cascade=CascadeType.ALL)
private Set<Hobby> hobbies = new HashSet<>();
@ManyToMany(cascade=CascadeType.ALL)
private Set<Person> people = new HashSet<>();
public void addPerson(Person p) {
this.people.add(p);
p.getHobbies().add(this);
}
Never use a mappedBy on both sides of the relationship. Simply only on the owning side |
Be aware for the following. Using a getter to get the Set of Hobbies out of person and than adding an item to the Set will eventually fail. You have to add a hobby through the owning class (in this case through Person) |
public void addHobby(Hobby h) {
this.hobbies.add(h);
h.getPeople().add(this);
}
FAQ
What is that Cascade thing?
-
When a person is deleted what happens to the hobby?
-
The Cascading defines what should happen to the underlying properties of an entity
-
In fact we have to tell something about assocations and specially regarding aggregations and compositions
-
Issues you might run into
Recursive rendering of ManyToMany relationships
-
When creating REST controller and GETting a result ends in some very large text in Postman and in Spring Boot the console print some kind of recursion error (java.lang.StackoverflowError)
-
During rendering the machine renders a list with Persons and in each person a List of Hobbies which on it’s turn have a List of Person which on it’s turn have a list of hobbies …
-
In fact you have a indirect recursion
-
-
Add @JsonIgnoreProperties("<some field>") above your field in your domain class which is the start of the problem (and it may be on both ends)
In our example using Person and Hobbies we have the problem when rendering the Hobbies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Person {
private String name;
@ManyToMany(...)
@JsonIgnoreProperties("people"); // <= people is the TO BE IGNORED field in the HOBBY class
private Set<Hobbies> hobbies = new HashSet<>();
}
public class Hobby {
private String name;
@ManyToMany(...)
@JsonIgnoreProperties("hobbies");
private Set<Person>) people = new HashSet<>();
}
If you have a lot of @JsonIgnoreProperties you can also add him to the class. The result is the union of all the mentioned properties |
DIY
-
Implement the above changes to your people project
-
Add Address-entity and add the @OneToOne relationship
-
Add Phone-entity and add the @OneToMany relationship
-
Add Hobby-entity and add the @ManyToMany relationship
-
-
Watch what happens during the starting of the application with your database-structure