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.

JPA @ManyToMany Unidirectional and Bidirectional

THERE ARE TWO NEW VERSIONS OF THIS POST.
MANY TO MANY SIMPLE: http://uaihebert.com/?p=1674&page=21
MANY TO MANY WITH AN EXTRA FIELD: http://uaihebert.com/?p=1674&page=22

Hello, good morning.

We will see today the @ManyToMany relationship Unidirectional and Bidirectional.

If want to set up an environment to run this code, you can check in the older posts about this subject: @OneToMany and @ManyToOne Unidirectional and Bidirectional, OneToOne Unidirectional and Bidirectional, Mapping two Tables in one Class, Mapping Date and Enum, Composite Primary-Key, SequenceGenerator, TableGenerator – Simple Primay Key, Auto Create Schema Script with: Ant, Hibernate 3 and JPA 2, Tutorial Hibernate 3 with JPA 2.

Let us work with a very easy user case, a notebook may have many owners (Person class), an owner may have many notebooks.

I will use the code from the older posts, I will only explain about the code related to the subject of this post.

Let us see the Person with a relationship Unidirectional:

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
}

The @JoinTable annotation was detailed in other post; if you do not write it in a @ManyToMany, the JPA will create one table by default; the created table name would be “PERSON_NOTEBOOK”.

The Notebook class:

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
}

And to create a relationship, run the code bellow:

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");
    }
}

After running the code, check your console:

Console Image.

You can see in the Console Image that the relationship was created correctly.

Check in your database and you will see that the relationship tables were created correctly.

Let us transform our code into a Bidirectional relationship.

Edit your Notebook class:

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
}

If you still with doubts about the concepts of Unidirectional and Bidirectional relationships, you can find the explanation here: JPA @OneToOne Unidirectional and Bidirectional.

In a @ManyToMany relationship any side can be the owner. Remember that the weak side (with the mappedBy), if persisted alone, it will not trigger the Cascade option that you find the owner side. If you only execute the Notebook.setPersons() before you persist the object, the relationship with person will not be updated/created, the weak side does not have this “power”.

I hope this post help you.

See you soon.