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.

Leave a Comment