Relacionamentos de tabela vs. relacionamentos de entidade
Em um sistema de banco de dados relacional, pode haver apenas três tipos de relacionamentos de tabela:
- um para muitos (por meio de uma coluna Chave estrangeira)
- individual (por meio de uma chave primária compartilhada)
- muitos-para-muitos (através de uma tabela de links com duas chaves estrangeiras referenciando duas tabelas pai separadas)
Portanto, um one-to-many
relacionamento de tabela é o seguinte:
Observe que o relacionamento é baseado na coluna Chave estrangeira (por exemplo, post_id
) na tabela filha.
Portanto, existe uma única fonte de verdade quando se trata de gerenciar um one-to-many
relacionamento de tabela.
Agora, se você usar um relacionamento de entidade bidirecional que mapeie o one-to-many
relacionamento de tabela que vimos anteriormente:
Se você der uma olhada no diagrama acima, poderá ver que existem duas maneiras de gerenciar esse relacionamento.
Na Post
entidade, você tem a comments
coleção:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
E, no PostComment
, a post
associação é mapeada da seguinte maneira:
@ManyToOne(
fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;
Portanto, você tem dois lados que podem alterar a associação da entidade:
- Ao adicionar uma entrada na
comments
coleção filha, uma nova post_comment
linha deve ser associada à post
entidade pai por meio de sua post_id
coluna.
- Ao definir a
post
propriedade da PostComment
entidade, a post_id
coluna também deve ser atualizada.
Como existem duas maneiras de representar a coluna Chave Externa, você deve definir qual é a fonte da verdade quando se trata de converter a alteração do estado da associação em sua modificação equivalente no valor da coluna Chave Externa.
MappedBy (também conhecido como lado inverso)
O mappedBy
atributo informa que o @ManyToOne
lado é responsável pelo gerenciamento da coluna Chave Externa, e a coleção é usada apenas para buscar as entidades filhas e fazer cascata de alterações no estado da entidade pai para filhos (por exemplo, remover o pai também deve remover as entidades filho).
É chamado de lado inverso porque faz referência à propriedade da entidade filha que gerencia esse relacionamento de tabela.
Sincronize os dois lados de uma associação bidirecional
Agora, mesmo se você definiu o mappedBy
atributo e a @ManyToOne
associação do lado filho gerencia a coluna Chave Externa, ainda é necessário sincronizar os dois lados da associação bidirecional.
A melhor maneira de fazer isso é adicionar esses dois métodos utilitários:
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
Os métodos addComment
e removeComment
garantem que ambos os lados estejam sincronizados. Portanto, se adicionarmos uma entidade filha, a entidade filha precisará apontar para o pai e a entidade pai deverá ter o filho contido na coleção filho.
Para obter mais detalhes sobre a melhor maneira de sincronizar todos os tipos de associação de entidade bidirecional, consulte este artigo .