JPA @OneToMany e @ManyToOne Unidirecional e Bidirecional

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=20

Olá, bom dia.

Vamos ver hoje o relacionamento @OneToMany e @ManyToOne Unidirecional e Bidirecional.

Podemos fazer o relacionamento @OneToMany de dois modos, utilizando a anotação @JoinColumn ou a anotação @JoinTable.

Irei utilizar o código de posts passados. Se você quiser montar um ambiente para executar o código do post, você pode olhar os outros posts sobre o assunto: @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.

Vou utilizar um simples exemplo, um Customer (cliente) pode ter vários cachorros, mas um Dog (cachorro) só pode ter um Customer.

Vamos ao código da classe Dog:

package com;

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

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    public Dog(){

    }

    public Dog(String name){
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;

    @Column
    private String name;

    //Getters and Setters
}

Repare que como nosso código é Unidirecional ele não faz menção do Customer.

Vamos ver agora, como ficará nossa classe Customer utilizando o @JoinTable:

package com;

import java.util.List;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = true, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name="USER_ID", nullable=true)
    private User user;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="CUSTOMER_HAS_DOGS", joinColumns={@JoinColumn(name="CUSTOMER_ID", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="DOG_ID", referencedColumnName="id")})
    private List dogs;

    //Getters and Setters
}

A anotação @JoinTable é bem simples e seu uso bem prático:

  • “name” – indica qual será a tabela que realizará a junção entre Customer e Dog (Por padrão colocamos o lado dominante como primeiro nome na tabela).
  • “joinColumns” – informa ao JPA um conjunto de chaves (um array separado por vírgulas) a ser utilizado para se identificar um registro. Poderia ser, por exemplo, o ID e o nome (“name”).
  • “@JoinColumn” – aponta uma coluna que servirá de chave primária na tabela de relacionamento. “name” é o nome que a coluna da tabela terá, e “referencedColumnName” é a chave primária da tabela dona do relacionamento; em nosso caso utilizamos id da tabela Customer. (Ao final do post veremos o real lado dominante desse relacionamento. Utilizo o Customer apenas para ficar didaticamente mais fácil)
  • “inverseJoinColumns” – faz o mapeamento das colunas da tabela do lado “dominado/fraco”.

Vamos inserir as informações no banco de dados? Abaixo o código que irá criar um relacionamento de um Customer com Dog (para configurar sua aplicação, verifique os links no começo do post e siga os passos):

package com;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            List dogs = new ArrayList();
            dogs.add(new Dog("Terminator"));
            dogs.add(new Dog("Fluffy"));
            dogs.add(new Dog("Bacon"));

            Customer customer = new Customer();
            customer.setName("Arnold");
            customer.setDogs(dogs);

            em.persist(customer);

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

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

Olhe os resultados:

Imagem Console.
Imagem banco de dados.

O JPA buscou o valor da sequence para cada objeto a ser inserido, inseriu cada registro na tabela, e depois fez o relacionamento na tabela “CUSTOMER_HAS_DOGS”.

Para utilizar o mapeamento @OneToMany sem uma tabela adicional, basta utilizar a anotação @JoinColumn ao invés de @JoinTable. Veja como nossa classe Customer ficará:

package com;

import java.util.List;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = true, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name="USER_ID", nullable=true)
    private User user;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="CUSTOMER_ID")
    private List dogs;

    //Getters and Setters
}

Agora a anotação @JoinColumn indica qual será a coluna utilizada para identificação.

Apague o SCHEMA do database antigo, crie novamente e veja o resultado após executar a classe Main:

Imagem do Console.
Imagem do banco de dados.

Veja que agora não existe mais uma tabela entre Customer e Dog. Na tabela Dog, foi criado uma coluna que fará essa referência.

E para tornar nosso relacionamento Bidirecional, vamos alterar a classe Dog:

package com;

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

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    public Dog(){

    }

    public Dog(String name){
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;

    @Column
    private String name;

    @ManyToOne(cascade=CascadeType.ALL)
    private Customer owner;    

    //Getters and Setters
}

A explicação da diferença entre Unidirecional e Bidirecional você encontra aqui: @OneToOne Unidirecional e Bidirecional.

Por padrão, a anotação @ManyToOne deve ser a dominante no relacionamento com @OneToMany. Você poderá notar que não existe a opção “mappedBy” para na anotação @ManyToOne, mas na anotação @OneToMany existe.

Para praticar, você poderia passar todas as configurações para a anotação @ManyToOne e colocar o parâmetro mappedBy em @OneToMany.

Espero que o post te hoje possa te ajudar.

Dúvida/Sugestão basta postar.

Até a próxima.

JPA @OneToMany and @ManyToOne Unidirectional and Bidirectional

THERE IS A NEW VERSION OF THIS POST.
CLICK HERE: http://uaihebert.com/?p=1674&page=20

Hello, good morning.

Let us see today about @OneToMany and @ManyToMany Unidirectional and Bidirectional relationship.

We can use the @OneToMany relationship with two annotations: @JoinColumn or @JoinTable.

I will use today the code from the older posts. If you want to set up an environment to run the code from this post, you can check the older posts: 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.

I will use a simple user case, a Customer can have many dogs but a Dog can have only a Customer.

The Dog class:

package com;

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

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    public Dog(){

    }

    public Dog(String name){
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;

    @Column
    private String name;

    //Getters and Setters
}

Notice that our Dog code is Unidirectional, it does not refer to the Customer class.

First we will see the Customer class with the @JoinTable annotation:

package com;

import java.util.List;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = true, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name="USER_ID", nullable=true)
    private User user;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="CUSTOMER_HAS_DOGS", joinColumns={@JoinColumn(name="CUSTOMER_ID", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="DOG_ID", referencedColumnName="id")})
    private List dogs;

    //Getters and Setters
}

The @JoinTable annotation is simple and easy to use:

  • “name” – indicates which table will do the “join” between the Dog and the Customer (It is a good practice to put in the table name: owner + dependent side).
  • “joinColumns” – “let the JPA know” through an array of keys that will identify a record. It could be, e.g., ID and the name columns.
  • “@JoinColumn” – indicates a column to be the primary key of the owning side in the relationship. “name” is the column name and the “referencedColumnName” is the primary key of the related class; in this relationship the owner is the Customer class. (In the end of this post we will see who the real owner of this relationship is).
  • “inverseJoinColumns” – defines the mapped columns of the “weak/dominated” side of the relationship.

Let us add some data to the database. I will post bellow the code that will create a relationship between the Customer and Dog (if you want to execute the code bellow, check the older posts about JPA listed in the beginning of this post):

package com;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            List dogs = new ArrayList();
            dogs.add(new Dog("Terminator"));
            dogs.add(new Dog("Fluffy"));
            dogs.add(new Dog("Bacon"));

            Customer customer = new Customer();
            customer.setName("Arnold");
            customer.setDogs(dogs);

            em.persist(customer);

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

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

Take a look at the results:

Console Image.

Database’s Image.

The JPA found the next sequence value to each object, inserted the objects and then inserted the relationship into the “CUSTOMER_HAS_DOGS”.

To use the @OneToMany annotation without an extra table, we can use the @JoinColumn annotation instead using the @JoinTable. Check out how our Customer class will look like:

package com;

import java.util.List;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = true, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name="USER_ID", nullable=true)
    private User user;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="CUSTOMER_ID")
    private List dogs;

    //Getters and Setters
}

The @JoinColumn indicates which column will be used as the ID.

Delete the database Schema and create it again. Run the Main class again and check out the final result:

Console Image.

Database’s Image.

Notice that there is no need of another table in the system to do the relationship. In the Dog table, a new column was created to store this value.

To transform this Unidirectional relationship into a Bidirectional relationship, let us change our Dog class:

package com;

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

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    public Dog(){

    }

    public Dog(String name){
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;

    @Column
    private String name;

    @ManyToOne(cascade=CascadeType.ALL)
    private Customer owner;    

    //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.

By default, the annotation @ManyToOne is the one that should be the owner in a relationship with @OneToMany. If you check the @ManyToOne annotation API you will not find the “mappedBy” as parameter.

If you want to practice more, you could pass all the parameters of the @OneToMany (Customer class) to the @ManyToOne (Dog class), and put in the @OneToMany the “mappedBy” parameter.

I hope that you enjoyed this post.

Doubts/Suggestions just post it.

See you soon.

JPA @OneToOne Unidirectional and Bidirectional

THERE IS A NEW VERSION OF THIS POST.
CLICK HERE: http://uaihebert.com/?p=1674&page=19

Hello, good morning.

Let us talk today about the @OneToOne relationship Unidirectional and Bidirectional. We often need to map several types of relationships and the JPA make it easier through annotations.

We will use today a simple example, a Customer has a User. In this example the Customer can have only one User and vice-versa.

I will be using the java code from the older posts. If you want to create a project and run the code from this post, you can check the older posts about JPA. In the older posts you will find the configurations, downloads link and tutorials teaching how to set up a JPA application: 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 see how a Unidirectional relationship looks like:

package com;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER, orphanRemoval = true)
    // @JoinColumn(name="USER_ID", nullable=false)
    @PrimaryKeyJoinColumn
    private User user;

    //Getters and Setters
}
package com;

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

@Entity
@Table(name="USER")
@SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE", allocationSize=1, initialValue=0)
public class User{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="USER_SEQUENCE")
    private int id;

    @Column
    private String login;

    @Column
    private String password;
    // Getters and Setters
}

About the @OneToOne annotations:

  • “cascade” – set triggers actions to the relationship. e.g.: If you delete a Customer the JPA can delete the User as well. We will talk about the “cascade” feature in another post.
  • “optional” – allow you to persist a Customer without a User; if true than you will not need to create a User before persisint the Customer (you will be able to find the Customer in the database, but if you do a Customer.getUser() you will get null as result). If your parameter value is false, when you persist a Customer you must have a User inside the Customer; you can set a User not persisted yet to the Csutomer.
  • “fetch” – the default value is EAGER; this value means that every time you search in the database for a Customer, the Customer User is search automatically. We will talk about this “fetch” feature in the future.
  • “orphanRemoval” – defines that a dependent entity without relationship must be removed from the database (in our model, the User depends on the Customer). If a User exists without a Customer, it will be deleted.

There are other two annotations to talk about, and one of them is commented (with //):

  • // @JoinColumn(name=“USER_ID”, nullable=“false”) – defines the database column that will be mapped into the attribute; it uses the parameter “name” to do this mapping and the “nullable” attribute is used to define if the attribute will required.
  • @PrimaryKeyJoinColumn – this annotation indicates to the JPA that to find a Customer User it just need to match the IDs; Our User will have the same ID that our Person.

To do a test, run the below code and you will see that a Customer and a User will be created; notice that the “persist” command is executed only in the Customer object:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = new Customer();
            customer.setName("John Doe");

            User user = new User();
            user.setLogin("jDoe");
            user.setPassword("123changeME!@#");

            customer.setUser(user);

            em.persist(customer);

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

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

Console Image.

If you want to search for the record in the database, you can use the below code:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = em.find(Customer.class, 1);

            System.out.println(customer.getName());
            System.out.println(customer.getUser().getLogin());

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

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

Console Image.

Notice that through the Customer we could get its User.

To transform our relationship in a bidirectional relationship, we need to edit the User class:

package com;

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

@Entity
@Table(name = "USER")
@SequenceGenerator(name = "USER_SEQUENCE", sequenceName = "USER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQUENCE")
    private int id;

    @Column
    private String login;

    @Column
    private String password;

    @OneToOne(mappedBy = "user")
    private Customer customer;

    //Getters and Setters
}

Notice that in the User class there is a reference to the Customer class; a @OneToOne annotation, in this reference, can be found. The parameter “mappedBy” indicates which class is the owner of this relationship, the stronger side. Pay attention to the fact that is not necessary to repeat any other mapping configuration, the JPA will use the Customer @OneToOne configurations.

What is “the thing” that makes Unidirectional not equal to the Bidirectional? When we had a Unidirectional relationship only the Customer class has a reference to the User class; you can only get a User by Customer.getUser() you can not do the other way. When we edit our User class we enabled the User to get the customer User.getCustomer().

A bidirectional relationship happens when both classes of a mapping contains multiple references. User HAS-A Customer and a Customer HAS-A User.

But, to persist into the database you will have to do add another code line:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = new Customer();
            customer.setName("John Doe");

            User user = new User();
            user.setLogin("jDoe");
            user.setPassword("123changeME!@#");

            // You must define a bidirectional relationship
			// like this
			customer.setUser(user);
            user.setCustomer(customer);

            em.persist(customer);

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

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

Pay attention that now we need to use the method User.setCustomer(Customer) and the Customer.setUser(User). Remember that Java works with references; we must “point” the classes to each other.

We can use any side of the relationship to do a search in the database. What if we use the User to do this search? Take a look in our code:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            User user = em.find(User.class, 2);

            System.out.println(user.getLogin());
            System.out.println(user.getCustomer().getName());

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

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

Console Image.

I hope this post might help you.

If you have any doubts/suggestions just post it.

See you soon.

JPA @OneToOne Unidirecional e Bidirecional

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=19

Olá, bom dia.

Vamos falar hoje sobre o relacionamento @OneToOne unidirecional e bidirecional. Diversas vezes precisamos mapear diferentes relacionamentos e o JPA facilita muito esse mapeamento através de anotações.

Iremos usar um simples exemplo, um Customer (cliente) tem um User (usuário). Onde um Customer pode ter apenas um User e vice-versa, um simples um para um.

Utilizarei o código dos outros artigos já utilizados. Caso você queira criar um projeto para executar o código aqui exibido, você poderá achar os passos necessários (configurações, downloads, tutoriais) nos primeiros posts sobre o assunto: 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 ver primeiro como ficaria o relacionamento Unidirecional?

package com;

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

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER, orphanRemoval = true)
    // @JoinColumn(name="USER_ID", nullable=false)
    @PrimaryKeyJoinColumn
    private User user;

    //Getters and Setters
}
package com;

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

@Entity
@Table(name="USER")
@SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE", allocationSize=1, initialValue=0)
public class User{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="USER_SEQUENCE")
    private int id;

    @Column
    private String login;

    @Column
    private String password;
    // Getters and Setters
}

Sobre os parâmetros da anotação @OneToOne:

  • “cascade” – define ações automatizadas no relacionamento, ex.: Ao apagar um Customer, apagar também um Usuário. Veremos sobre “cascade” em um post futuro.
  • “optional” – você não será obrigado a ter um User ao persistir um Customer, ou seja, você não tem que criar um usuário para satisfazer essa condição (você poderá buscar o Customer no banco de dados, mas Customer.getUser() terá null como resposta). Com o valor igual a false, ao se cadastrar um Customer, é obrigatória a presença de um User. Pode ser um User recém ainda não persistido.
  • “fetch” – o valor padrão é EAGER. Ou seja, ao carregar o Customer já será feita a consulta relacionada ao User de modo automático. Iremos ver sobre esse assunto em um post futuro.
  • “orphanRemoval” – define que uma entidade dependente, caso não tenha relacionamento, será removida do banco de dados (em nosso modelo, User depende de Customer). Caso exista um User sem Customer, esse user será removido.

Existem também duas anotações sendo que uma delas está comentada:

  • // @JoinColumn(name=”USER_ID”, nullable=false) – define qual é a coluna mapeada para fazer a união na consulta. É indicado o nome da coluna através do parâmetro “name” e que esse campo não pode ser nulo pelo parâmetro “nullable”.
  • @PrimaryKeyJoinColumn – essa anotação indica ao JPA que, para encontrar um objeto User basta procurar um registro com o mesmo ID do Customer. Ou seja, indica que um User vai ter o mesmo ID que seu Customer.

Para fazer um teste, execute o código abaixo para ver que será criado um User e um Customer; mesmo o comando de “persist” sendo executado apenas com o Customer:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = new Customer();
            customer.setName("John Doe");

            User user = new User();
            user.setLogin("jDoe");
            user.setPassword("123changeME!@#");

            customer.setUser(user);

            em.persist(customer);

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

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

Imagem Console.

Realizando uma consulta, eu utilizei o método “find”, você irá encontrar o seguinte resultado:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = em.find(Customer.class, 1);

            System.out.println(customer.getName());
            System.out.println(customer.getUser().getLogin());

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

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

Imagem Console.

Note que através do Customer conseguimos buscar o usuário relacionado.

Para fazer nosso relacionamento bidirecional vamos alterar nossa classe User:

package com;

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

@Entity
@Table(name = "USER")
@SequenceGenerator(name = "USER_SEQUENCE", sequenceName = "USER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQUENCE")
    private int id;

    @Column
    private String login;

    @Column
    private String password;

    @OneToOne(mappedBy = "user")
    private Customer customer;

    //Getters and Setters
}

Repare que agora temos uma referência à classe Customer e com mapeamento @OneToOne. O parâmetro “mappedBy” indica quem é o owner desse relacionamento, o lado mais forte. Repare que não foi necessário repetir nenhum código do mapeamento pois em nossa classe Customer já está tudo configurado.

Qual a diferença de um relacionamento unidirecional e um bidirecional? Repare que na Unidirecional apenas Customer tem referência User, ou seja, só é possível fazer Customer.getUser(). Como alteramos nossa classe User agora podemos fazer User.getCustomer().

Resumindo, um relacionamento bidirecional é quando duas classes de um mapeamento contêm referências mútuas. User TEM-UM Customer e Customer TEM-UM User.

Mas, para criar persistir no banco de dados é diferente. Vamos ver como ficará nossa classe Main para criar um registro:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Customer customer = new Customer();
            customer.setName("John Doe");

            User user = new User();
            user.setLogin("jDoe");
            user.setPassword("123changeME!@#");

            // You must define a bidirectional relationship
			// like this
			customer.setUser(user);
            user.setCustomer(customer);

            em.persist(customer);

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

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

Como diferença note que foi necessário utilizar o método User.setCustomer(Customer) e também Customer.setUser(User). Lembre-se que o java em si trabalha com referências, então precisamos sim apontar uma classe para a outra.

E depois, basta consultar em qualquer lado do relacionamento. Vamos consultar pelo User agora? Veja como nosso código ficará:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            User user = em.find(User.class, 2);

            System.out.println(user.getLogin());
            System.out.println(user.getCustomer().getName());

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

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

Imagem do Console.

Espero que esse post possa ter te ajudado.

Qualquer dúvida/sugestão basta colocar.

Até a próxima.

JPA Mapping two Tables in one Class

THERE IS A NEW VERSION OF THIS POST.
CLICK HERE: http://uaihebert.com/?p=1674&page=11

Hello, good evening.

We will see today how to map two tables in one class. We will see a simple approach to get this task done.

If you want to run the code that I will post here, you can see in the older posts how to set up your application; there you will find the download link and the step-by-step of how to set up your application. The others JPA posts are (starting from the newest to the oldest): 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.

I will be using the Postgres database, and I will post here a SQL script to create the tables and the needed records. If you have any doubts about how to set up your application (e.g. persistence.xml, libraries, build path) check out the older posts about this subjects. I will post here just the needed data to this post.

CREATE TABLE hello.person
(
  id integer NOT NULL,
  "name" character varying(255) NOT NULL
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.person OWNER TO postgres;

CREATE TABLE hello.health_care
(
  id integer NOT NULL,
  "company_name" character varying(255)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.health_care OWNER TO postgres;

-- Insert a person and his healt care company
INSERT INTO hello.person values (1 , 'john');
INSERT INTO hello.health_care values ( 1, 'best ever');

It will be a simple case, a person that has a health care. Let us suppose that this health care is not controlled by your application, but for another application of your company.

In our case, we will not create a HealthCare class because it has one field only, the health care company name; the system architects decided to only add this field to the Person class.

Let us see how our Person class will be:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;

@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;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

About the Person class:

  • The @SecondaryTable annotation “tells” to the JPA that there is another table with some data of the Person class.
  • The parameter pkJoinColumns of the @SecondaryTable annotation it is used to indicate which column the JPA will use as relationship. We did not indicate any field in the @SecondaryTable annotation to specify the relationship between the tables person and health_care; the JPA by default will match the person table ID with the health_care id ([person]id == [health_care]id).
  • In the @Column annotation of the “companyName” attribute, we notify the JPA in which table it will find attribute value through the “table” parameter.

I will write bellow, a code that will find our record Person in the database:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Person person = em.find(Person.class, 1);

            System.out.println(person.getName());
            System.out.println(person.getCompanyName());

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

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

Run the main class code and check the result:

Console Image.

Notice that the company name came as it were part of the Person class.

Do you have any question/suggestion?

Just post it.

See you later.

JPA Mapeando Duas Tabelas em uma Classe

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=11

Olá, boa tarde.

Vamos ver hoje como mapear duas tabelas em uma classe. Veremos uma abordagem simples para conseguirmos realizar essa tarefa.

Caso você precise criar o ambiente necessário para executar uma aplicação com JPA, você pode acessar os primeiros posts que contém os links para download e o passo a passo das configurações. Os outros posts sobre JPA são (do mais recente para o mais antigo): 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.

Estarei utilizando aqui o banco de dados Postgres, e irei postar o script para se criar as tabelas e inserir um registro em cada. Caso você tenha dúvidas de como configurar sua aplicação (ex.: persistence.xml, bibliotecas, build path) visite os primeiros posts sobre o assunto. Vou colocar aqui, apenas o básico.

CREATE TABLE hello.person
(
  id integer NOT NULL,
  "name" character varying(255) NOT NULL
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.person OWNER TO postgres;

CREATE TABLE hello.health_care
(
  id integer NOT NULL,
  "company_name" character varying(255)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.health_care OWNER TO postgres;

-- Insert a person and his healt care company
INSERT INTO hello.person values (1 , 'john');
INSERT INTO hello.health_care values ( 1, 'best ever');

Um caso simples onde a pessoa tem um plano de saúde. Mas imagine que esse plano de saúde não é controlado pela sua aplicação, ela é mantida por outra aplicação.

Em nosso caso, não é necessário criar uma classe PlanoDeSaude, pois como queremos apenas exibir o nome do plano de saúde, ele foi incorporado à classe Person (Pessoa).

Vamos ver agora como ficará nossa classe Person:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;

@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;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Sobre o código acima:

  • A anotação @SecondaryTable indica ao JPA que existe outra tabela que contém dados da classe atual.
  • O parâmetro pkJoinColumns da anotação @SecondaryTable serve para indicar qual a chave que faz a junção. Como não indicamos nenhuma chave do lado da classe Person na anotação @SecondaryTable, o JPA irá utilizar a chave primária da Person (person_id == health_care_id).
  • Na anotação @Column do atributo companyName, informamos em qual tabela o JPA irá procurar o campo através do parâmetro “table”.

Vou colocar abaixo, como executar uma busca simples:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

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

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

            Person person = em.find(Person.class, 1);

            System.out.println(person.getName());
            System.out.println(person.getCompanyName());

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

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

Execute o código e veja o resultado:

Imagem Console.

Note que o nome da empresa veio como se fizesse parte da classe Person.

Caso você tenha alguma dúvida/sugestão basta postar.

Até a próxima.