Por que é necessária a noção de um lado dono:
A idéia de um lado proprietário de uma relação bidirecional deriva do fato de que nos bancos de dados relacionais não existem relações bidirecionais, como no caso de objetos. Nos bancos de dados, temos apenas relações unidirecionais - chaves estrangeiras.
Qual é o motivo do nome 'dono'?
O lado proprietário da relação rastreada pelo Hibernate é o lado da relação que possui a chave estrangeira no banco de dados.
Qual é o problema que a noção de possuir lado resolve?
Veja um exemplo de duas entidades mapeadas sem declarar um lado proprietário:
@Entity
@Table(name="PERSONS")
public class Person {
@OneToMany
private List<IdDocument> idDocuments;
}
@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
@ManyToOne
private Person person;
}
Do ponto de vista do OO, esse mapeamento define não uma relação bidirecional, mas duas relações unidirecionais separadas.
O mapeamento criaria não apenas tabelas PERSONS
e ID_DOCUMENTS
, mas também criaria uma terceira tabela de associação 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)
)
Observe a chave primária pk
em ID_DOCUMENTS
somente. Nesse caso, o Hibernate controla os dois lados da relação independentemente: Se você adicionar um documento à relação Person.idDocuments
, ele inserirá um registro na tabela de associação PERSON_ID_DOCUMENTS
.
Por outro lado, se chamarmos idDocument.setPerson(person)
, alteramos a chave estrangeira person_id na tabela ID_DOCUMENTS
. O Hibernate está criando duas relações unidirecionais (chave estrangeira) no banco de dados, para implementar uma relação bidirecional de objetos.
Como a noção de possuir lado resolve o problema:
Muitas vezes o que nós queremos é apenas uma chave estrangeira na tabela de ID_DOCUMENTS
direção PERSONS
ea mesa associação extra.
Para resolver isso, precisamos configurar o Hibernate para parar de rastrear as modificações na relação Person.idDocuments
. O Hibernate deve rastrear apenas o outro lado da relação IdDocument.person
e, para isso, adicionamos mappedBy :
@OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
O que significa mappedBy?
Isso significa algo como: "as modificações deste lado da relação já estão mapeadas pelo
outro lado da relação IdDocument.person, portanto, não é necessário rastreá-lo aqui separadamente em uma tabela extra".
Existem GOTCHAs, consequências?
Usando mappedBy , Se nós só chamar person.getDocuments().add(document)
, a chave estrangeira em ID_DOCUMENTS
vão NÃO estar ligado ao novo documento, porque esta não é a / lateral proprietária rastreado da relação!
Para vincular o documento à nova pessoa, você precisa ligar explicitamente document.setPerson(person)
, porque esse é o lado proprietário da relação.
Ao usar mappedBy , é de responsabilidade do desenvolvedor saber qual é o lado proprietário e atualizar o lado correto da relação para acionar a persistência da nova relação no banco de dados.