The idea of a owning side of a bidirectional relation comes from the fact that in relational databases there are no bidirectional relations like in the case of objects.
In databases we only have foreign keys, where only one table can have a foreign key to another. Let's take an example that would not work as expected and see why mappedBy is necessary:
@Entity
@Table(name="PERSONS")
public class Person {
@OneToMany
private List<IdDocument> idDocuments;
}
@Entity
@Table(name="IDDOCUMENT")
public class IdDocument {
@ManyToOne
private Person person;
}
This would create not only tables PERSONS and IDDOCUMENTS, but would also create a third table PERSONS_IDDOCUMENTS:
CREATE TABLE persons_iddocument
(
persons_id bigint NOT NULL,
iddocuments_id bigint NOT NULL,
CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
CONSTRAINT fk_docs FOREIGN KEY (iddocuments_id) REFERENCES iddocument (id),
CONSTRAINT pk UNIQUE (iddocuments_id)
)
Notice the primary key on documents only. In this case Hibernate tracks both sides of the relation independently: If you add a document to relation Person.idDocuments, it inserts a record in PERSON_IDDOCUMENTS.
If we change the Person of a IdDocument, it changes the foreign key person_id on table IDDOCUMENTS.
Hibernate is creating two unidirectional (foreign key) relations on the database, to implement one bidirectional object relation, because databases do not support bidirectional relations.
But what we want is for the object relation to be only mapped by the foreign key on table IDDOCUMENTS towards PERSON: one document belongs to only one person.
There is no need for the extra table, that would force us to modify both Person.idDocuments and IdDocument.person inside the same database transaction to keep the relation consistent.
To solve this we need to configure Hibernate to stop tracking the modifications on relation Person.idDocuments. Hibernate should only track the other side of the relation IdDocument.person, and to do so we add mappedBy:
@OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
This means "modifications on this side of the relation are already Mapped By by the other side of the relation IdDocument.person, so no need to track it here separately in an extra table".
This gives us the mapping we want, but has one major consequence:
- Modifications on the Person.idDocuments collection are no longer tracked by Hibernate, and it is the responsibility of the developer to modify IdDocument.person instead in order to modify the association.