[RESOLVIDO] 2 mapeamentos @ManyToMany para mesma entidade

11 respostas
rogerio.alcantara

Boa tarde Jedis do GUJ, tudo bem?

Tenho um problema que não sei nem como pesquisar na net por ele. Se vcs me ajudarem só nisso eu já agradeço e tento me virar.

Seguinte, eu tenho:
@Entity
class Employee {

       @ManyToMany
       List<Classification> classification;

       @ManyToMany
       List<Classification> interest;
}
Isso significa que eu preciso guardar o ramo de atividade e as áreas de interesse dele (q é a mesma entidade Classification).

O hibernate gerou apenas uma tabela para essas duas relações. Assim:

Employee_Classification
- Employee_Id
- classification_id
- interest_id

Até aí tudo bem, achei a solução até interessante.

O problema, é na hora de atualizar os dados nessa tabela. Olha que legal:

Eu adiciono novos itens e persisto, ok, sem problemas.

Mas quando eu faço um update, ele exclui os itens de uma relação.

Eu acompanhei o log gerado pelo hibernate e que o acontece é o seguinte:
-- vai salvar a relação classification:
-- DELETE * FROM Employee_Classification WHERE Employee_Id = xpto;
-- insere todos os itens da coleção classification;

--vai salvar a relação interests:
-- DELETE * FROM Employee_Classification WHERE Employee_Id = xpto; <-------- (aqui está o problema)
-- insere todos os itens da coleção interest
Reparam no que aconteceu?

O segundo delete (que acontece quando vai inserir a coleção interests), remove os intens da coleção classification que acabaram de ser inseridos.

=/

Alguém já passou por isso ou por alguma situação semelhante?

Ou tem como eu forçar que o hibernate crie uma tabela para cada relação?

Valeu pela atenção turma.

11 Respostas

Hebert_Coelho

Quando você atualizar o Employee, a lista com a lista classification preenchida?

Se não estiver, ele vai limar o relacionamento.

rogerio.alcantara

Olha o jakefrog me salvando, rs…

Intaum, eu salvo as duas de uma vez e as duas listas estão preenchidas e atualizadas.

(ou seja, as duas precisam ser salvas mesmo)

Hebert_Coelho

Mas elas estão “attached” com a sessão?

Tipo, busca a entidade por um find, altera o nome e depois persiste?

rogerio.alcantara
Acho que sim. O processo é o seguinte:
POST>Save()

-- cria List<Classificatoin> classifications com os ids passados no POST;

-- cria List<Classificatoin> interests com os ids passados no POST;

-- carrega o employee via dao.loadById(idDoFulano); //que carrega a lista de classification e interest via LAZY

-- employee.clearClassifications();
-- employee.addClassifications(classifications);

-- employee.clearInterests();
-- employee.addInterests(interests);

-- dao.saveOrUpdate(employee);
Por tanto, acho que está tudo "attached" sim.

O q vc acha?

R

Se você usar a anotação @Column para mudar os nomes das colunas não resolve?

rogerio.alcantara

Olá Rafael, muito obrigado pela resposta.

Eu não sei se eu entendi direito o que vc quis dizer. Eu fiz:
@Entity
class Employee {

	@ManyToMany
	@Column(name="Employee_Classification")
	private List<Classification> classification;

	@ManyToMany
	@Column(name="Employee_Interest")
	private List<Classification> interests;
}
E eu não percebi nenhuma diferença - o hibernate ignorou e manteve a tabela com a mesma estrutura.

Foi isso mesmo que vc quis dizer?

Hebert_Coelho

employee.clearClassifications();
employee.addClassifications(classifications);

Vc sempre limpa para adicionar tudo? Será que essa lista que você adiciona não está com menos objetos?

Não sei se esse seria o comportamento correto.

Outra coisa é “carrega o employee via dao.loadById(idDoFulano);”

Será que esse load é eager? Você tem certeza de que a lista está vindo?

rogerio.alcantara

Mais uma vez muito obrigado pelo retorno e pela atençao jakefrog.

O dao.loadById(idDoFulano) simplesmente encapsula o entityManager.find(Employee.class, id). Intaum acho que carrega certinho sim.

As duas listas são LAZY. Mas elas são carregas no momento em que eu dou um clearLista();

Sim, eu sempre limpo pra adicionar tudo. Pois esse método é chamado no final de uma operação onde a pessoa fica brincando com a lista, adicionando e removendo itens nela.

Ou seja, pode ser que tenha menos objetos do que antes sim e que esses objetos sejam diferentes.

Não sei se ficou claro…

Será que não há nenhuma forma de forçar o hibernate a criar 2 tableas, uma para cada relação?

Hebert_Coelho

Existe sim.

Basta utilizar um JoinTable para casa relacionamento. Aqui eu mostro como: JPA @ManyToMany Unidirecional e Bidirecional.

rogerio.alcantara

Ótima idéia.

Vou tentar e escrevo o resultado.

Mais uma vez muito obrigado pela atenção.

rogerio.alcantara

Resolvido 100% com a dica do mano jakefrog.

Ficou assim:
@Entity  
class Employee {  
  
    @ManyToMany  
	@JoinTable(name="Employee_Classification", 
				joinColumns= {
					@JoinColumn(name="Employee_Id", referencedColumnName="Id")},
				inverseJoinColumns={
					@JoinColumn(name="Classification_Id", referencedColumnName="Id")})
    private List<Classification> classification;  
  
    @ManyToMany  
	@JoinTable(name="Employee_Interest",
				joinColumns= {
					@JoinColumn(name="Employee_Id", referencedColumnName="Id")},
				inverseJoinColumns={
					@JoinColumn(name="Classification_Id", referencedColumnName="Id")})
    private List<Classification> interests;  
}
Isso resultou na criação de duas tabelas: Employee_Classification e Employee_Interest.

Dessa forma, os updates ocorreram normalmente, sem uma coleção interferir na outra.

Mais uma vez, muito obrigado jakefrog. ;)

Criado 7 de dezembro de 2011
Ultima resposta 7 de dez. de 2011
Respostas 11
Participantes 3