Como essa é uma pergunta muito comum, escrevi
este artigo , no qual essa resposta se baseia.
Associação unidirecional um para muitos
Como expliquei neste artigo , se você usar a @OneToMany
anotação com @JoinColumn
, terá uma associação unidirecional, como a que existe entre a Post
entidade pai e o filho PostComment
no diagrama a seguir:
Ao usar uma associação unidirecional um para muitos, apenas o lado dos pais mapeia a associação.
Neste exemplo, apenas a Post
entidade definirá uma @OneToMany
associação à PostComment
entidade filha :
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();
Associação bidirecional um para muitos
Se você usar o @OneToMany
com o mappedBy
conjunto de atributos, você terá uma associação bidirecional. No nosso caso, a Post
entidade possui uma coleção de PostComment
entidades filhas e a PostComment
entidade filha possui uma referência à Post
entidade pai , conforme ilustrado no diagrama a seguir:
Na PostComment
entidade, a post
propriedade da entidade é mapeada da seguinte maneira:
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
A razão por que definir explicitamente o fetch
atributo para FetchType.LAZY
é porque, por padrão, todos @ManyToOne
e @OneToOne
associações são buscadas avidamente, o que pode causar N + 1 questões da consulta. Para mais detalhes sobre este tópico, consulte este artigo .
Na Post
entidade, a comments
associação é mapeada da seguinte maneira:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
O mappedBy
atributo da @OneToMany
anotação faz referência à post
propriedade na PostComment
entidade filha e, dessa forma, o Hibernate sabe que a associação bidirecional é controlada pelo @ManyToOne
lado, responsável por gerenciar o valor da coluna Chave Externa na qual o relacionamento da tabela se baseia.
Para uma associação bidirecional, você também precisa ter dois métodos utilitários, como addChild
e removeChild
:
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
Esses dois métodos garantem que os dois lados da associação bidirecional não sejam sincronizados. Sem sincronizar as duas extremidades, o Hibernate não garante que as mudanças no estado da associação sejam propagadas para o banco de dados.
Para obter mais detalhes sobre o melhor modo de sincronizar associações bidirecionais com JPA e Hibernate, consulte este artigo .
Qual escolher?
A associação unidirecional @OneToMany
não funciona muito bem ; portanto, você deve evitá-la.
É melhor usar o bidirecional @OneToMany
que é mais eficiente .