Why is the notion of a owning side necessary:
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 unidirectional relations - foreign keys.
What is the reason for the name 'owning side'?
The owning side of the relation tracked by Hibernate is the side of the relation that owns the foreign key in the database.
What is the problem that the notion of owning side solves?
Take an example of two entities mapped without declaring a owning side:
@Entity
@Table(name="PERSONS")
public class Person {
@OneToMany
private List<IdDocument> idDocuments;
}
@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
@ManyToOne
private Person person;
}
From a OO point of view this mapping defines not one bi-directional relation, but two separate uni-directional relations.
The mapping would create not only tables PERSONS
and ID_DOCUMENTS
, but would also create a third association table PERSONS_ID_DOCUMENTS
:
CREATE TABLE PERSONS_ID_DOCUMENTS
(
persons_id bigint NOT NULL,
id_documents_id bigint NOT NULL,
CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
CONSTRAINT fk_docs FOREIGN KEY (id_documents_id) REFERENCES id_documents (id),
CONSTRAINT pk UNIQUE (id_documents_id)
)
Notice the primary key pk
on ID_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 the association table PERSON_ID_DOCUMENTS
.
On the other hand, if we call idDocument.setPerson(person)
, we change the foreign key person_id on table ID_DOCUMENTS
. Hibernate is creating two unidirectional (foreign key) relations on the database, to implement one bidirectional object relation.
How the notion of owning side solves the problem:
Many times what we want is only a foreign key on table ID_DOCUMENTS
towards PERSONS
and the extra association table.
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;
What does it mean mappedBy ?
This means something like: "modifications on this side of the relation are already Mapped By
the other side of the relation IdDocument.person, so no need to
track it here separately in an extra table."
Are there any GOTCHAs, consequences?
Using mappedBy, If we only call person.getDocuments().add(document)
, the foreign key in ID_DOCUMENTS
will NOT be linked to the new document, because this is not the owning /tracked side of the relation!
To link the document to the new person, you need to explicitly call document.setPerson(person)
, because that is the owning side of the relation.
When using mappedBy, it is the responsibility of the developer to know what is the owning side, and update the correct side of the relation in order to trigger the persistence of the new relation in the database.
Your last snippet of Java code doesn't compile. I guess it looks like
parent.getChilds().clear(); // note: you should name it children rather than childs
parent.setChilds(someNewSetOfChildren):
Don't do the last instruction. Instead of replacing the set by another one, clear the set and add the new children to the cleared set:
parent.clearChildren();
parent.addChildren(someNewSetOfChildren);
where the methods are defined as:
public void clearChildren() {
this.children.clear();
}
public void addChildren(Collection<Child> children) {
this.children.addAll(children);
}
The setChildren method should be removed completely, or it should be replaced with the following implementation:
public void setChildren(Collection<Child> children) {
this.children.clear();
this.children.addAll(children);
}
Best Answer
Check all of the places where you are assigning something to sonEntities. The link you referenced distinctly points out creating a new HashSet but you can have this error anytime you reassign the set. For example:
Usually you want to only "new" the set once in a constructor. Any time you want to add or delete something to the list you have to modify the contents of the list instead of assigning a new list.
To add children:
To remove children: