JPA Mapping Date and Enum

Hello, good afternoon.

Let us see today how to map in JPA the Date attribute and the Enum attribute.

Maybe there are people that almost got a heart attack when they hear about Date in Java. The APIs can be a little complex to those that are learning about Java.

Fortunately we can find a good solution in JPA to persist a Date attribute. The @Temporal annotation allows us to map 3 options:

  • Just date.
  • Just time.
  • Date and Time.

Check the code bellow:

@Temporal(value=TemporalType.DATE)
private Date onlyDate;

@Temporal(value=TemporalType.TIME)
private Date onlyTime;

@Temporal(value=TemporalType.TIMESTAMP)
private Date dateAndTime;

It is a very simply way to persist a date field. You can choose the attribute information type just using the right annotation type.

To map an Enum is easy as mapping a Date. To map an Enum in JPA you just have to write the code bellow:

@Enumerated
private Enum vaules;

@Enumerated(value=EnumType.STRING)
private Enum vauleAsString;

@Enumerated(value=EnumType.ORDINAL)
private Enum vauleAsNumber;

You may leave the @Enumerated without parameters, or you may define it as: String or Ordinal.

If your table is not a huge table, you can define your Enum field as String. It is easier to read a status = ‘OK’ or ‘NOK’ than status = 1 (same than status = ‘OK’).

Notice that a query using a String as parameter will use more processing from the database than using a number; if your table is a huge table, it is a better idea to have your status as number and another table to store the status description.

Another solution (less elegant) it would be having both columns in the same table, a column with status = ‘1’ and another column with status_type = ‘OK’.

I hope this little post might be able to help you.

If you have any Doubts/Suggestions just post it.

See you soon.

JPA Mapeando Datas (Date) e Enum

Bom dia, tudo bem?

Hoje vamos ver sobre como mapear atributo (s) do tipo Date (java.util.Date) ou Enum.

Muitas pessoas ao ouvirem a palavra “data” em Java já têm uma parada cardíaca. As APIs que tratam sobre data podem ser um pouco confusas no começo.

Felizmente encontramos uma boa solução quando falamos de mapear data em JPA. A anotação @Temporal nos permite mapear 3 opções:

  • Apenas data.
  • Apenas hora.
  • Data e Hora.

Veja como ficaria seu código:

@Temporal(value=TemporalType.DATE)
private Date onlyDate;

@Temporal(value=TemporalType.TIME)
private Date onlyTime;

@Temporal(value=TemporalType.TIMESTAMP)
private Date dateAndTime;

Fica bem simples salvar data desse modo. Você pode escolher qual o tipo de informação salvar apenas pela anotação.

E para mapear um Enum é mais simples ainda. Para mapear um Enum em JPA basta colocar conforme o código abaixo:

@Enumerated
private Enum vaules;

@Enumerated(value=EnumType.STRING)
private Enum vauleAsString;

@Enumerated(value=EnumType.ORDINAL)
private Enum vauleAsNumber;

Você pode optar por deixar a anotação @Enumerated sem parâmetro algum, ou então pode definir seu Enum como: String ou Ordinal (numérico).

Caso sua tabela não seja grande seria uma boa idéia colocar como String. É muito mais fácil identificar status = OK ou NOK do que identificar que status = 1 é (status = OK).

Mas lembre-se de que, uma consulta de String custa mais processamento ao banco de dados do que uma consulta por número inteiro, se sua tabela for grande considere ter o status (ou qualquer outra coluna de Enum) como numero e ter uma tabela onde todos esses valores são listados.

Uma outra solução (menos elegante) seria ter as 2 colunas na mesma tabela, com código status = 1 e descrição status_type = ‘OK’.

Espero que esse pequeno post de hoje possa ter te ajudado.

Dúvida/Sugestões/Críticas basta colocar.

Até a próxima.

Tutorial JPA Composite Primary-Key

THERE ARE TWO NEW VERSIONS OF THIS POST.
SIMPLES COMPOSITE KEY: http://uaihebert.com/?p=1674&page=8
COMPLEX COMPOSITE KEY: http://uaihebert.com/?p=1674&page=9

Good afternoon.

Let us talk today about Composite Primary Key (Primary-Key) in a class?

What if only the ID it is not enough to define a unique record of your class? How can we make the JPA understand this situation of two fields as primary-key?

To help us to understand about Composite Key I will use a class named Car; this class has a car chassis serial number as primary key. Imagine that a new software requirement just arrive saying that, we need the Car primary key to be composed by the chassis serial number and with the engine serial number.

We will keep our JPA study at the same point that we have stopped in the last post (JPA SequenceGenerator). If you need any help to compile the code of this post, you can check the others posts about JPA that shows how to set up the environment: JPA TableGenerator – Simple Primay Key, Auto Create Schema Script with: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 with JPA 2.

We need to create a class to be our composite primary-key.
Let us see how the CarPK code will be:

package com;

import java.io.Serializable;

public class CarPK implements Serializable {

    private String chassisSerialNumber;
    private String engineSerialNumber;

    public CarPK(){
        // Your class must have a no-arq constructor
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof CarPK){
            CarPK carPk = (CarPK) obj;

            if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
                return false;
            }

            if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
                return false;
            }

            return true;
        }

        return false;
    }

    @Override
    public int hashCode() {
        return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
    }

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }
}

There are some rules that your PK class should follow:

  • It must have a default constructor without arguments.
  • It must implement the java.io.Serializable interface.
  • It must override the methods equals and hashCode.

Let us create now the Car class:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

@Entity
@Table(name="CAR")
@IdClass(value=CarPK.class)
public class Car {

    @Id
    private String chassisSerialNumber;
    @Id
    private String engineSerialNumber;

    @Column
    private String name; // Yes, some people like to give name to theirs cars.

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }

    public String getName() {
        return name;
    }

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

Notice that in our Car class, we just added the @Id annotation without the need of any other annotation type. PS.: At the “name” attribute you will find the @Column annotation but this annotation is not necessary in our case.

Let us see our Main class code that will insert a record into 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();

            Car car = new Car();

            car.setChassisSerialNumber("9BW DA05X6 1 T050136");
            car.setEngineSerialNumber("ABC123");
            car.setName("Thunder");

            em.persist(car);

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

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

Run the Main class and check the result in the console.

Console Image.
Database Image.

How can we find our recorded entity that uses composite primary-key? Let us edit our Main class and see the result:

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();

            CarPK carPK = new CarPK();

            carPK.setChassisSerialNumber("9BW DA05X6 1 T050136");
            carPK.setEngineSerialNumber("ABC123");

            Car car = em.find(Car.class, carPK);

            System.out.println(car.getName());

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

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

Run the Main class again.

Console Image.

To find an entity that uses its ID as composite primary-key we need to create an instance of the PK class and use it as parameter in the “find” method.

There is another way to map this primary-key attribute. Notice that we have the same ID fields in both classes: “Car and CarPK“. It both has the chassisSerialNumber and the engineSerialNumber fields. With a little lines added/removed from our code we can refactor it to remove this duplicated fields.

package com;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class CarPK implements Serializable {

    @Column
    private String chassisSerialNumber;

    @Column
    private String engineSerialNumber;

    public CarPK(){
        // Your class must have a no-arq constructor
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof CarPK){
            CarPK carPk = (CarPK) obj;

            if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
                return false;
            }

            if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
                return false;
            }

            return true;
        }

        return false;
    }

    @Override
    public int hashCode() {
        return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
    }

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "CAR")
public class Car {

    @EmbeddedId
    private CarPK carPK;

    @Column
    private String name; // Yes, some people like to give name to theirs cars.

    public String getName() {
        return name;
    }

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

    public CarPK getCarPK() {
        return carPK;
    }

    public void setCarPK(CarPK carPK) {
        this.carPK = carPK;
    }
}

We can see that just a few changes were done in the classes:

  • In the CarPK class there is a new annotation: the @Column. The car ID attributes will be mapped only inside the CarPK. There is a new annotation named @Embeddeable allowing our class to be part of another class.
  • We removed the Id attributes from the Car class. We also removed the @IdClass annotation. We added an attribute of the CarPK with the @EmbeddedId, this annotation allow the Car to use the CarPK fields as its primary-key.

If you wish, run the main class again and you will see that our class is returned by the find method without errors.

Warning: When your class implements the composite primary-key it will not be able to use the sequence id generation. You will have to generate the ID by your software code.

Do you have any doubts or suggestions? Just post it.

See you later.

Tutorial JPA Chave Primária Composta

EXISTE DOIS NOVOS POSTS SOBRE ESSE ASSUNTO:
CHAVE COMPOSTA SIMPLES: http://uaihebert.com/?p=1622&page=8
CHAVE COMPOSTA COMPLEXA: http://uaihebert.com/?p=1622&page=9

Bom dia.

Vamos falar hoje sobre Chave Primária Composta (Composite Key)?

Imagine que apenas o ID não seria suficiente para definir a chave primária da sua classe. Como fazer com que o JPA entenda esse mapeamento?

Vou utilizar como exemplo uma classe Car (Carro). Imagine um sistema onde para se identificar um carro, é necessário o número do chassi. Vamos supor que um novo requisito chegou e além do chassi será necessário o código de identificação do motor.

Iremos continuar exatamente do último post sobre JPA (JPA SequenceGenerator). Você poderá ver os outros posts sobre JPA caso precise de alguma ajuda para montar o ambiente necessário para rodar o código desse post: JPA TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2,Tutorial Hibernate 3 com JPA 2.

Será necessário criar uma classe para fazer o trabalho da chave composta. Vamos ver como ficará o código da classe CarPK:

package com;

import java.io.Serializable;

public class CarPK implements Serializable {

    private String chassisSerialNumber;
    private String engineSerialNumber;

    public CarPK(){
        // Your class must have a no-arq constructor
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof CarPK){
            CarPK carPk = (CarPK) obj;

            if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
                return false;
            }

            if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
                return false;
            }

            return true;
        }

        return false;
    }

    @Override
    public int hashCode() {
        return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
    }

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }
}

Existem algumas normas que sua classe de chave composta deve seguir:

  • Deve ter um construtor sem argumentos
  • Deve implementar a interface java.io.Serializable
  • Deve sobrescrever os métodos equals e hashCode

Agora vamos criar nossa classe Car:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

@Entity
@Table(name="CAR")
@IdClass(value=CarPK.class)
public class Car {

    @Id
    private String chassisSerialNumber;
    @Id
    private String engineSerialNumber;

    @Column
    private String name; // Yes, some people like to give name to theirs cars.

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }

    public String getName() {
        return name;
    }

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

Repare que em nossa classe Car, apenas adicionamos a anotação @Id sem nos preocupar em definir qualquer outro tipo de anotação. Uma observação é que no atributo “name” existe a anotação @Column mas ela não é obrigatória.

Veja o código da classe Main que irá inserir um objeto da classe Car (carro) em nosso banco de dados:

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();

            Car car = new Car();

            car.setChassisSerialNumber("9BW DA05X6 1 T050136");
            car.setEngineSerialNumber("ABC123");
            car.setName("Thunder");

            em.persist(car);

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

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

Vamos executar a classe Main e ver o resultado.

Imagem do Console.
Imagem Banco de Dados.

E como consultar uma entidade que tem a chave primária composta? Vamos alterar nossa classe Main para executar essa pesquisa:

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();

            CarPK carPK = new CarPK();

            carPK.setChassisSerialNumber("9BW DA05X6 1 T050136");
            carPK.setEngineSerialNumber("ABC123");

            Car car = em.find(Car.class, carPK);

            System.out.println(car.getName());

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

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

E após executar a classe:

Imagem do Console.

Para consultar uma entidade que tem sua chave primaria (primary-key) composta é necessário se criar uma instância da dessa chave e passá-la como parâmetro na consulta.

Vou mostrar outro modo de se mapear uma chave primária composta. Repare que atualmente nós temos os mesmo campos dentro da classe CarPK e Car. Ambos contêm o código do chassi e o código do motor. Podemos fazer uma pequena alteração no código para solucionar isso.

package com;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class CarPK implements Serializable {

    @Column
    private String chassisSerialNumber;

    @Column
    private String engineSerialNumber;

    public CarPK(){
        // Your class must have a no-arq constructor
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof CarPK)){
            CarPK carPk = (CarPK) obj;

            if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
                return false;
            }

            if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
                return false;
            }

            return true;
        }

        return false;
    }

    @Override
    public int hashCode() {
        return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
    }

    public String getChassisSerialNumber() {
        return chassisSerialNumber;
    }

    public void setChassisSerialNumber(String chassisSerialNumber) {
        this.chassisSerialNumber = chassisSerialNumber;
    }

    public String getEngineSerialNumber() {
        return engineSerialNumber;
    }

    public void setEngineSerialNumber(String engineSerialNumber) {
        this.engineSerialNumber = engineSerialNumber;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "CAR")
public class Car {

    @EmbeddedId
    private CarPK carPK;

    @Column
    private String name; // Yes, some people like to give name to theirs cars.

    public String getName() {
        return name;
    }

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

    public CarPK getCarPK() {
        return carPK;
    }

    public void setCarPK(CarPK carPK) {
        this.carPK = carPK;
    }
}

Pequenas alterações foram feitas.

  • Na classe CarPK agora existe a anotação @Column. Esses serão a partir de agora os atributos mapeados no banco de dados. Foi adicionada também a anotação @Embeddeable informando que essa classe pode ser incorporada em outra classe.
  • Na classe Car foram retirados os atributos e substituídos por um atributo da classe CarPK. Foi retirado também a anotação @IdClass. Agora colocamos uma outra anotação chamada @EmbeddedId que informa que ao JPA que os campos a serem utilizados virão de dentro da classe CarPK.

Caso você queria, execute a classe Main novamente e verá que a consulta será realizada normalmente.

Atenção
: Ao utilizar do recurso de chave primária composta não será possível utilizar uma “sequence” para gerar o ID automaticamente. Você terá que gerar o ID por código.

Alguma dúvida? Sugestão? Basta colocar abaixo.

Até mais.

JPA SequenceGenerator

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

Hello, how are you?

Let us talk today about a Primary Key generator named “SequenceGenerator”. In the last post (JPA TableGenerator – Simple Primay Key) we talked about the TableGenerator and how to solve the fact of having only one Sequence to all tables in our system.

What if we see today how to create a sequence per Table (Class)? If the TableGenerator is giving your code the feeling of “a dirty code”, we can eliminate this “feeling” removing the TableGenerator and using the SequenceGenerator instead.

With a sequence per table we have the same Key Generation that we have using the TableGenerator, but with less configuration code inside our classes.

I remember that we will be using in this post the Hibernate implementation and the JPA implementation provided by Hibernate. If you wish, you can use any JPA implementation that provides automatic schema generation.

I will start exactly where we stopped in the last post (JPA TableGenerator – Simple Primay Key). We will do some updates in the class User and Dog replacing the TableGenerator for SequenceGenerator.

I will write bellow how our classes were and how it will be. If you want to set up the environment to run the code, in this post (JPA TableGenerator – Simple Primay Key) you can see the tutorial step by step.

How our classesconfigurations are today:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Hello" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="postgres" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.default_schema" value="hello"/>
        </properties>
    </persistence-unit>
</persistence>
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER")
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @TableGenerator(name="USER_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="USER_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="USER_GENERATOR")
    private int id;

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="DOG")
public class Dog {

    @TableGenerator(name="DOG_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="DOG_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="DOG_GENERATOR")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

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

public class Main {

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

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

            User user = new User();
            user.setName("abc123");
            user.setPassword("abc123");
            em.persist(user);

            Dog dog = new Dog();
            dog.setName("pineapple");
            em.persist(dog);

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

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

The lines with the @TableGenerator annotation indicate the TableGeneration Strategy code that we use. There are a lot of lines to do a simple function.

To update your code to SequenceGenerator you just have to edit the code has the some lines of the bellow code:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name="USER")
@SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE", allocationSize=1, initialValue=0)
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

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

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

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

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

The code above with the @SequenceGenerator indicate the lines that you will have to change to replace the TableGenerator for SequenceGenerator.

Let us see more details about the SequenceGenerator parameters:

  • name = the sequence name. The ID will use this name as a key to locate the created sequence.
  • sequenceName = name of the sequence that will be created (or used) in the database.
  • allocationSize = The value that will be incremented for each new database record. The default value is 1 but, if we set to 2 the first record will have the ID 2, the next 4…
  • initialValue = The sequence start value.

Let us run the Main class and see the results:

Console Image.

Notice that the Hibernate did a query searching for the next id value. The Hibernate created the sequence when we start up the application, this creation process occurs just when the sequence is not located.

Sequence Image.

I hope this post might help you.

If you have any question/suggestion just post it.

See you later.

JPA SequenceGenerator

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

Olá pessoal, tudo bem?

Vamos falar hoje sobre o modo de geração de Primary Key chamado “SequenceGenerator“. No ultimo post (JPA TableGenerator – Chave Primária Simples) falamos sobre o TableGenerator e como resolver o fato de termos apenas uma Sequence para todas as tabelas.

Que tal hoje vermos como gerar uma Sequence por Tabela (Classe)? Caso o fato de ter uma tabela para gerar códigos tenha deixado sua classe nada elegante, podemos arrumar esse pequeno “incomodo” alterando de TableGenerator para SequenceGenerator.

Tendo uma Sequence por tabela nos trará o mesmo resultado de termos uma tabela para guardar o valor da próxima PK de cada classe.

Lembro que estaremos utilizando o Hibernate e sua implementação do JPA. Caso você queira, poderá utilizar qualquer outra implementação do JPA que forneça uma criação automática de schema.

Irei continuar exatamente do último post (JPA TableGenerator – Chave Primária Simples), onde iremos apenas realizar, a alteração nas classes User e Dog, de TableGenerator para SequenceGenerator.

Colocarei abaixo como estão nossas classes e como ficarão. Caso você queira montar o ambiente para que você possa executar o código abaixo, basta ir no tópico JPA TableGenerator – Chave Primária Simples que você verá o passo a passo.

Como estão nossas classesconfigurações hoje:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Hello" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="postgres" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.default_schema" value="hello"/>
        </properties>
    </persistence-unit>
</persistence>
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER")
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @TableGenerator(name="USER_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="USER_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="USER_GENERATOR")
    private int id;

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="DOG")
public class Dog {

    @TableGenerator(name="DOG_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="DOG_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="DOG_GENERATOR")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

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

public class Main {

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

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

            User user = new User();
            user.setName("abc123");
            user.setPassword("abc123");
            em.persist(user);

            Dog dog = new Dog();
            dog.setName("pineapple");
            em.persist(dog);

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

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

O código com a anotação @TableGenerator atualmente utiliza essa estratégia. Realmente são várias linhas de código para uma função simples.

Para alterar o seu código para SequenceGenerator basta alterar o acima código para:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name="USER")
@SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE", allocationSize=1, initialValue=0)
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

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

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

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

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

As linhas de códigos que contém a anotação @SequenceGenerator representam a alteração necessária para que nossa classe fosse da estratégia de TableGenerator para SequenceGenerator.

Vou explicar sobre os parâmetros do SequenceGenerator:

  • name = nome da seqüência. Esse é o nome utilizado pelo ID ao localizar a seqüência criada.
  • sequenceName = nome da seqüência que será criada(ou utilizada caso já exista) no banco de dados.
  • allocationSize = O valor que será acrescido a cada novo registro. Estamos adicionando sempre um, caso fosse 2 o primeiro usuário criado teria seu ID 2 o segundo 4 e assim vai.
  • initialValue = valor inicial da sequence.

Vamos executar a classe Main e ver o resultado?
Imagem do Console.

Repare que já foi feita a consulta na sequence para saber qual o próximo valor. A sequence foi criada no momento que executamos o sistema, e isso ocorre apenas quando a sequence não existe no banco de dados ainda.
Imagem Sequences criadas.

Espero que esse post possa ter lhe ajudado.

Dúvidas/Críticas/Sugestões basta comentar.

Até a próxima

JPA TableGenerator – Simple Primay Key

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

Good morning, how are you?

Today we will talk about a JPA resource named TableGenerator. In the first post about JPA (Tutorial Hibernate 3 with JPA 2), the Hibernate created an automatic way do generate the ID, it created a sequence. This sequence (“hibernate_sequence”) has the responsibility to keep the ID of our User class, and provide the next ID to be used.

The problem is that when you persist your first User, his ID number will be 1. If you persist another User his ID will be 2. But if you persist a Dog its ID will be 3, even if it is your first persisted Dog.

TableGenerator is a solution to this kind of “problem/situation”.

If you wish to see how to install and configure a database and setup a Hello World JPA/Hibernate application, you can see it here (Tutorial Hibernate 3 with JPA 2).

The only thing that will not be the same from the first post (Tutorial Hibernate 3 with JPA 2) is that I will be using the Postgres database instead MySQL. The installation and configuration process are the same.

Do not forget to create a schema named “Hello” in your database.

Let us start with the needed downloads, Hibernate/JPA3. We will be using the JPA implementation provided by the Hibernate that you will find in the downloaded file.

I will be using the Postgres as database, so I have also downloaded the Driver (JDBC4 Postgres DriverIf you want to search for other Driver versions click here). You will be able to use the database that you desire. In the first post you can see how to set up the MySQL database (Tutorial Hibernate 3 with JPA 2).

Create a project of the type “Java Project”. Create also a folder named “lib” inside the folder “src”. The lib folder must have all the jar files (Driver file and the Hibernate/JPA libraries). It should have the same files as the files displayed in this picture. In the post Tutorial Hibernate 3 with JPA 2 you can see how to do this steep by steep.

We need to add these files to our application Build Path. We need to open the menu by clicking with the right button of the mouse on the project > Properties > Java Build Path > Add Jars. Select the JAR files inside the lib folder. In the post “Tutorial Hibernate 3 with JPA 2” you can see how to do this steep by steep.

Create a folder named “META-INF” inside the folder “src”. Inside the folder “META-INF” you will have to create a file named “persistence.xml” and past the code bellow into it (In the post “Tutorial Hibernate 3 with JPA 2” you can see how to do this steep by steep).

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Hello" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.show_sql" value="true" />
			
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
			
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="postgres" />
            
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.default_schema" value="hello"/>
        </properties>
    </persistence-unit>
</persistence>

The bolded lines indicate where you have to change if you wish to use another database.

Let us create now the classes that will be persisted. We will have a class named User and another class named Dog.

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER")
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @TableGenerator(name="USER_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="USER_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="USER_GENERATOR")
    private int id;

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() = this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="DOG")
public class Dog {

    @TableGenerator(name="DOG_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="DOG_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="DOG_GENERATOR")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

I will talk about each parameter in the annotation:

  • name = TableGenerator created name. The ID annotation will use it searching for and identification.
  • table = table which will store the created primary keys. In our case, the “persistence.xml” has some attributes allowing the automatic table creation (<property name=”hibernate.hbm2ddl.auto” value=”update”/>). That is the reason that we did not need to create this table, when the Main class is executed this table is already created.
  • pkColumnName = name of the column that will store a String with the ID name. In our case, this name is defined by the parameter pkColumnValue that has the value “USER_ID” (you will see in the end of this post, a screen displaying the value stored in the database).
  • valueColumnName = the column name that will record the value that our ID counter has.
  • pkColumnValue = value that will be used as a pair with the valueColumnName. i.e.: “USER_ID | 1” and then “USER_ID | 2”
  • allocationSize = represents the value that will be added to the ID every time that you persist an object. The default is one but if you set to 2, your first User will have the ID 2 and the next will have the ID 4.

To run the application we need to create a class with a main method. Let us name our class Main:

package com;

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

public class Main {

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

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

            User user = new User();
            user.setName("abc123");
            user.setPassword("abc123");
            em.persist(user);

            Dog dog = new Dog();
            dog.setName("pineapple");
            em.persist(dog);

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

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

After you run the Main class, just run some queries in the database that you will see the result matches with the lines displayed in our Console:

Console

User table query

Dog table query

Primary Key table query

The value in the primary key table is 2 and it is not a bug, this table stores the next value to be used. Before you persist a new value, the Hibernate will check the current value, use it and then increase the value.

Today I used the Hibernate in this tutorial, but you could use any persistence provider (e.g. Hibernate, EclipseLink, etc) that provides an automatic schema generation to do this tutorial.

Do you have any question or suggestion? Just post bellow that I will answer.

See you later.

JPA TableGenerator – Chave Primária Simples

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

Bom dia, tudo bem você?

Vamos ver hoje como utilizar o recurso chamado TableGenerator. No primeiro post sobre o assunto (Tutorial Hibernate 3 com JPA 2), o Hibernate criou de modo automático para gerar o id da classe, uma sequence. Essa sequence (“hibernate_sequence”) é responsável por armazenar o ID da classe User, e sempre fornecer o próximo número do ID de um novo objeto a ser inserido no DB.

Com isso, se você criar um usuário o ID seria 1 (um). O próximo usuário criado teria seu ID igual a 2. Caso você criasse uma classe Cachorro e mandasse incluir no banco de dados, o ID do cachorro seria 3 mesmo sendo o primeiro cachorro criado.

O TableGenerator vem como uma solução alternativa caso essa abordagem de sequence te gere algum problema.

Se você quiser ver uma abordagem detalhada de como criar/configurar uma aplicação desde a instalação de banco de dados e configurações você pode ver nesse tópico aqui: Tutorial Hibernate 3 com JPA 2.

A única diferença do post de hoje para o primeiro post com um Hello World (Tutorial Hibernate 3 com JPA 2), é que estarei utilizando o Postgres como banco de dados e não o MySQL. O processo de instalação e configuração é o mesmo.

Não se esqueça de criar o schema no banco de dados que você estiver utilizando. Em nosso caso estaremos utilizando um schema chamado Hello.

Vamos começar com os downloads, Hibernate/JPA3. Estaremos utilizando a implementação do Hibernate que é encontrada no arquivo que você irá fazer o download.

No meu caso, estou utilizando o banco de dados do Postgres, será necessário fazer o download do Driver (JDBC4 Postgresql DriverCaso você queria procurar Drivers mais novos.). Você poderá utilizar qualquer outro banco de dados. No primeiro post mostra a configuração do MySQL (Tutorial Hibernate 3 com JPA 2).

Após criar um projeto do tipo “Java Project”, crie uma pasta com o nome “lib” dentro da pasta “src”. Dentro dela deve ficar todos os arquivos do tipo jar (tanto o Drive como as bibliotecas do Hibernate). Deve ficar como nessa foto. No post Tutorial Hibernate 3 com JPA 2 ensina esse processo de modo detalhado.

Precisamos adicionar os arquivos ao Build Path da aplicação. Botão direito sobre o nome do projeto > Properties > Java Build Path > Add Jars. Selecione os arquivos que você colocou dentro da pasta lib. No post Tutorial Hibernate 3 com JPA 2 ensina esse processo de modo detalhado.

Crie uma pasta chamada “META-INF” dentro da pasta “src”. Dentro da pasta “META-INF” crie um arquivo chamado “persistence.xml” e cole o código abaixo. (Passo a passo aqui Tutorial Hibernate 3 com JPA 2).

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Hello" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.show_sql" value="true" />
			
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
			
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="postgres" />
            
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.default_schema" value="hello"/>
        </properties>
    </persistence-unit>
</persistence>

As linhas em destaque são as linhas que precisariam sofrer alteração caso você utilize um banco de dados diferente.

Vamos criar agora as classes que serão persistidas. Vamos utilizar uma classe User e uma classe Dog.

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER")
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @TableGenerator(name="USER_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="USER_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="USER_GENERATOR")
    private int id;

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() = this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="DOG")
public class Dog {

    @TableGenerator(name="DOG_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="DOG_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="DOG_GENERATOR")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

Vou explicar os campos da anotação TableGenerator:

  • name = Nome dado ao TableGenerator criado. Ele será utilizado pelo ID ao buscar por uma identificação.
  • table = tabela que será utilizada para armazenar as chaves primárias criadas. Em nosso caso, o “persistence.xml” está marcado para criar as tabelas que ainda não existem de modo automático (“<property name=”hibernate.hbm2ddl.auto” value=”update”/>”). Por esse motivo não é necessário criarmos essa tabela, pois após a execução da classe Main, essa tabela já existirá em nosso banco de dados.
  • pkColumnName = nome da coluna em que irá gravar um texto contendo o nome do ID. Em nosso caso, esse nome é definido através do pkColumnValue que é USER_ID. (Você verá ao final, em uma imagem, como esse valor é armazenado na tabela).
  • valueColumnName = nome da coluna que irá registrar o valor do contador que irá sempre incrementar nosso ID.
  • pkColumnValue = Valor que servirá de par para o valueColumnName. Por exemplo: “USER_ID | 1″ e depois “USER_ID | 2″
  • allocationSize = O valor que será acrescido a cada novo registro. Estamos adicionando sempre um, caso fosse 2 o primeiro usuário criado teria seu ID 2 o segundo 4 e assim vai.

E por último precisamos de uma classe que execute nosso código, realizando a persistência no banco de dados.

package com;

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

public class Main {

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

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

            User user = new User();
            user.setName("abc123");
            user.setPassword("abc123");
            em.persist(user);

            Dog dog = new Dog();
            dog.setName("pineapple");
            em.persist(dog);

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

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

Após executar a classe Main, basta consultar no banco de dados os 3 resultados que devem aparecer de acordo com o que foi exibido no console.

Console

Consulta tabela User

Consulta tabela Dog

Consulta a tabela de PKs

O valor na tabela de chaves primárias está como 2 não é por que deu algum erro, mas por que ele salva o valor da próxima chave a ser gerada. Quando for inserir um novo registro, o Hibernate irá consultar qual o próximo valor, utilizará, e salvará o valor acrescido de um.

Apesar de utilizar o Hibernate no exemplo de hoje, qualquer outro provedor de persistência (Hibernate, EclipseLink, etc) que forneça geração automática de schema, poderá ser utilizado para esse exemplo.

Ficou alguma dúvida? Sugestão? Basta comentar que irei responder.

Até a próxima.