JPA @ManyToMany Unidirecional e Bidirecional

EXISTEM DUAS NOVAS VERSÕES DESSE POST.
MANY TO MANY SIMPLES: http://uaihebert.com/?p=1622&page=21
MANY TO MANY COM CAMPO EXTRA: http://uaihebert.com/?p=1622&page=22

Pessoal, bom dia.

Vamos falar hoje sobre o relacionamento @ManyToMany Unidirecional e Bidirecional.

Caso você tenha dúvidas em como criar o ambiente necessário para executar o código, basta olhar os posts mais antigos sobre JPA: JPA @OneToMany e @ManyToOne Unidirecional e Bidirecional, @OneToOne Unidirecional e Bidirecional, Mapeando Duas Tabelas em uma Classe, Mapeando Datas (Date) e Enum, Chave Primária Composta, SequenceGenerator, TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 com JPA 2.

Vamos imaginar um simples caso de uso, um notebook (classe Notebook) pode ter vários donos (classe Person), e uma pessoa pode ter vários notebooks.

Estarei utilizando código de posts anteriores, então só explicarei o necessário para o código desse post.

Vamos ao código da classe Person com o relacionamento Unidirecional:

package com;

import java.util.List;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name = "person")
@SecondaryTable(name = "health_care", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "id") })
public class Person {

    @Id
    private int id;

    @Column
    private String name;

    @Column(table = "health_care", name = "company_name")
    private String companyName;

    @ManyToMany
    @JoinTable(name="person_has_notebooks", joinColumns={@JoinColumn(name="person_id")}, inverseJoinColumns={@JoinColumn(name="notebook_id")})
    private List notebooks;

    // Getters and setters
}

A anotação @JoinTable já foi citada em outro post, caso você não a especifique, o JPA criará uma tabela padrão; o nome dessa tabela seria “PERSON_NOTEBOOK“.

E a classe Notebook:

package com;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name="notebook")
public class Notebook {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String serialNumber;
    private int ramMemoryTotal;
    private int hdSpaceTotal;

    // Getters and setters
}

Para criar o relacionamento execute o código abaixo:

package com;

//Using the * to make the import list smaller
import javax.persistence.*;
import java.util.*;

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            Notebook noteA = new Notebook();
            noteA.setSerialNumber("A0123");
            Notebook noteB = new Notebook();
            noteB.setSerialNumber("B0123");
            Notebook noteC = new Notebook();
            noteC.setSerialNumber("C0123");

            List notebooks = new ArrayList();
            notebooks.add(noteA);
            notebooks.add(noteB);
            notebooks.add(noteC);

            Person person = new Person();
            person.setName("Zorro");
            person.setNotebooks(notebooks);

            em.persist(person);

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}

Execute o código veja o seu resultado:

Imagem do Console.

Como podemos perceber o console nos mostra que o relacionamento foi criado corretamente.

Verifique seu banco de dados e verás que a tabela de relacionamento foi criada corretamente.

Vamos fazer com que nosso relacionamento seja bidirecional?

Vamos alterar a classe Notebook:

package com;

import java.util.List;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name="notebook")
public class Notebook {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String serialNumber;
    private int ramMemoryTotal;
    private int hdSpaceTotal;

    @ManyToMany(mappedBy="notebooks")
    private List persons;

    // Getters and setters
}

A diferença entre um relacionamento unidirecional e bidirecional você poderá ver nesse post: @OneToOne Unidirecional e Bidirecional.

Em um relacionamento @ManyToMany qualquer um dos lados do relacionamento pode ser o lado dominante. Lembre-se que o lado dominado (descrito com mappedBy), se persistido apenas ele, ele não irá disparar o Cascade do lado dominante. Em outras palavras. Ao se fazer Notebook.setPersons() apenas antes salvar o objeto, o relacionamento com as pessoas não será atualizado/criado, pois o lado dominado não tem esse “poder”.

Espero que o post de hoje possa te ajudar.

Até a próxima.

22 thoughts on “JPA @ManyToMany Unidirecional e Bidirecional

  1. Na verdade gostaria de saber como criar uma coluna PK com valor auto Incremental em uma tabela secundaria, ou seja que foi criada a partir de um @JoinTable, usando associação @ManytoMany. Tenho uma Promoção e um Produto, onde Promoção possui uma instância de produto, na tabela secundaria foi gerado duas colunas (id_product, id_promotion), gostaria de add uma terceira coluna na tabela secundaria. Já faz alguns dias que procuro resolver isso :/ Se puder ajuda ficarei agradecido. Abraço

    • Jonasrn, boa tarde.

      Você tira o relacionamento fazendo setObjeto(null) e depois exclui.

      Obrigado pela visita.

    • Você me passa fácil mano. [=

      Só estudar e ralar que rapidinho você vai estar dando palestras e tudo mais. [=

      Obrigado pelo apoio!

      Até mais. o_

      • Muita coisa que aprendi aqui no uaihebert me ajudou a ser um desenvolvedor mais capaz, inclusive fui convidado pelos fundadores do grupo de usuários java daqui do estado para participar do congresso que eles realizam todo ano, onde ministrei um mini-curso de JSF2 com JPA2.

        Agora e estudo e rumo a certificação.

        Abraços

  2. Pela milésima vez sou salvo pelo seus posts, tenho aprendido bastante aqui com você, e tenho passado esse conhecimento para outros. Deus te abençoe ricamente.

  3. Hebert,
    Como fazer para excluir o relacionamento a partir da entidade dominada? Isto é possível? Porque a partir da entidade dominante o JPA já faz isso automaticamente.

  4. Hebert, como vai?

    Você disse que “Em um relacionamento @ManyToMany qualquer um dos lados do relacionamento pode ser o lado dominante” … Mas, AMBOS podem ser o lado dominante? Por exemplo, eu tenho um relacionamento unidirecinal e por isso não posso excluir o lado dominado pois recebo um erro. É possível torná-lo dominante sem que a outra ponta torne-se o dominado, mas permaneça como dominante??

    Agradecida!!

    • Valéria, boa noite.

      Um dos lados deve ser o dominante, mas não os dois lados.

      Antes de excluir, você deve remover o relacionamento. Algo como:
      b.setA(null);
      entityManager.remove(b);

      Obrigado pela visita.

  5. Olá hebert, muito bom seu trabalho e seus post’s, estou com uma duvida e ainda não consegui a solução, neste caso de relacionamento N pra N, como faço para trazer minha lista(atributo da classe) ordenado pelo campo que eu quero?

Leave a Comment