Bidirecional
Uma outra perspectiva do sentido de um relacionamento, nós permite definir os relacionamentos bidirecionais. Na prática, estes relacionamentos indicam que há um relacionamento em ambos os sentidos entre as entidades.
Diferemente dos relacionamentos unidirecionais, os bidirecionais necessitam de mapeamento em ambas as entidades, uma vez que se relacionam, comportando-se como se existessem dois relacionamentos unidirecionais (um para cada entidade envolvida).
Nos relacionamentos bidirecionais temos o conceito de Entidade possuidora e Entidade inverso.
- Entidade possuidora: A tabela dessa entidade será a possuidora da chave estrangeira.
- Entidade inverso: O atributo deve ser anotado e configurado com
mappedBy
.
Um para Um
No geral, os mapeamentos bidirecionais, não se diferenciam muito quanto ao uso das anotações.
Conforme podemos observar, no Código a seguir, temos um relacionamento Um para Um entre as entidades Gerente
e Departamento
. Quando realizarmos o mapeamento, vamos definir uma coluna na tabela Gerente
que faz referência a chave primária de Departamento
.
@Entity
public class Departamento {
@OneToOne(mappedBy="departamento")
private Gerente gerente;
}
// Agora precisamos mapear em ambas as entidades o relacionamento
@Entity
public class Gerente {
@OneToOne
@JoinColumn(name="DEPARTAMENTO_ID")
private Departamento departamento;
}
Nota:
A entidade Inverso, leva a anotação
@OneToOne
com o parâmetromappedBy
.A entidade Possuidora, leva a anotação
@JoinColumn
. Porém, essa o uso dessa anotação, assim com a@Column
não é obrigatória para identificarmos o relacionamento.
É importante destacar que o parâmetro declarado no mappedBy
deve ter o mesmo nome do atributo que se desejar mapear. Neste exemplo, utilizamos, na entidade Departamento
, mappedBy="departamento"
e o atributo da entidade Gerente
o atributo com nome departamento
.
Além disso, nos relacionamentos bidirecionais, precisamos fazer a atribuição nas duas entidades, conforme visto no Código a seguir.
Gerente gerente = new Gerente();
Departamento departamento = new Departamento();
gerente.setDepartamento(departamento);
departamento.setGerente(gerente);
Um para Muitos e Muitos para Um
Nos relacionamentos unidirecionais temos duas maneiras de mapear o relacionamento de uma para muitas entidades, com as anotações @OneToMany
e @ManyToOne
. Entretanto, quando realizamos um mapeamento bidirecional temos uma única forma de fazê-lo.
Conforme podemos observar, no Código a seguir, temos um relacionamento Um para Muitos entre as entidades Gerente
e Projeto
; e, outro relacionamento de Muitos para Um entre Projeto
e Gerente
.
Quando realizarmos o mapeamento, será criada uma tabela auxiliar para armazenar as chaves de Gerente
e Projeto
. Contudo, sempre que necessitarmos de uma instância das entidades envolvidas no relacionamento bidirecional, o provider precisará realizar uma junção entre as três tabelas. Esse procedimento pode causar uma diminuição de performance da aplicação.
Uma outra estratégia permite que seja definida uma coluna na tabela Projeto
que faz referência a chave primária de Gerente
. Para isso, utilizamos a anotação @JoinColumn
, no lado muitos do relacionamento.
@Entity
public class Projeto {
@ManyToOne
@JoinColumn(name="GERENTE_ID")
private Gerente gerente;
}
@Entity
public class Gerente {
@OneToMany(mappedBy="gerente")
private Set<Projeto> projetos;
}
Nota:
A especificação exige que o lado possuidor do relacionamento seja o lado Muitos e não o Um.
Muitos para Muitos
Na prática, um relacionamento Muitos para Muitos bidirecional se diferencia do unidirecional por manter referências em ambas as entidades. Como no mapeamento unidirecional, também será criada uma tabela auxiliar para manter as chaves estrangeiras das duas tabelas.
Conforme podemos observar, no Código a seguir, temos um relacionamento Muitos para Muitos entre as entidades Funcionario
e Projeto
; e, outro relacionamento de Muitos para Muitos entre Projeto
e Funcionario
.
@Entity
public class Projeto {
@ManyToMany(mappedBy = "projetos")
private Set<Funcionario> funcionarios;
}
@Entity
public class Funcionario {
@ManyToMany
@JoinTable(name = "TrabalhaEmProjeto"
joinColumns = @JoinColumn(name = "func_id"),
inverseJoinColumns = @JoinColumn(name = "proj_id"))
private List<Projeto> projetos;
}
Nota:
No relacionamento bidirecional de Muitos para Muitos não faz diferença a entidade que será a possuidora ou inversa, pois sempre será gerada a tabela auxiliar.
Exercício
- Conforme descrição a seguir, implemente as classes e seus respectivos mapeamentos.
Uma empresa está organizada em departamentos. Cada departamento tem um nome único, um número único e um empregado que o gerencia.
Um departamento controla um número qualquer de empregados e projetos, onde, cada qual deve conter um único nome, um único número e uma única localização.
Armazenamos o nome de cada empregado, o número do seu seguro social, endereço, salário, sexo e data de nascimento. Um empregado está alocado em um departamento, e deve trabalhar em diversos projetos que são controlados por este departamento