ADMFactory
Tutorials from a developer perspective

How to generate tables from entities using EclipseLink

by ADM

 

 


In this tutorial, I will show you how to generate entities from tables using EclipseLink.

This method is good when you already have the database and you want to access it using EclipseLink.

The Eclipse project used in this tutorial can be found on GitHub. Also, if you follow the commits you can see different steps that are described in this tutorial.

Database

Because I don't have a database as example I will create 2 simple tables using MySQL Workbench:

The tables will be in one-to-one relationship. The SQL script to generate these 2 tables and the relation between look like:

-- MySQL Workbench Forward Engineering

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema db
-- -----------------------------------------------------
DROP SCHEMA IF EXISTS `db` ;

-- -----------------------------------------------------
-- Schema db
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `db` DEFAULT CHARACTER SET utf8 ;
USE `db` ;

-- -----------------------------------------------------
-- Table `db`.`user_detail`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db`.`user_detail` ;

CREATE TABLE IF NOT EXISTS `db`.`user_detail` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `address` VARCHAR(255) NULL DEFAULT NULL,
  `postal_code` VARCHAR(20) NULL DEFAULT NULL,
  `city` VARCHAR(100) NULL DEFAULT NULL,
  `phone_number` VARCHAR(45) NULL DEFAULT NULL,
  `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE INDEX `id_UNIQUE` (`id` ASC),
  PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = utf8;


-- -----------------------------------------------------
-- Table `db`.`user`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db`.`user` ;

CREATE TABLE IF NOT EXISTS `db`.`user` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `email` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `email_UNIQUE` (`email` ASC),
  UNIQUE INDEX `id_UNIQUE` (`id` ASC),
  CONSTRAINT `fk_user_user_detail`
    FOREIGN KEY (`id`)
    REFERENCES `db`.`user_detail` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = utf8;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Create the project

I will create a maven project from Eclipse. If you need help follow the How to create an Application with Maven in Eclipse tutorial.

The source code for the entire project can be found on GitHub.

Generate Entities

Note: If your Eclipse is not setup with a database connection follow the Configure database connection in Eclipse tutorial.

To generate the entities select the project, right-click, select JPA Tools --> Generate Entities from Tables...

Select the connection and then the 2 tables we just created.

Next, you can edit the relationship between the entities and the entities names.

In this step, I will select the association one-to-one and disable any other associations. Also, I will add only one reference to user entity to point to the user_detail entity. Make sure to select cascade all.

Next, you can select the source folder, package name, key generation, fetch type, collection type.

Note: for MySQL AUTO_INCREMENT property we need to select Key generator as identify.

Note: for Associations fetch I will use Lazy as I want to load data only if is needed.

Next screen will let us edit more variables and names.

Note: I will use for id columns long and for dates (created and updated): java.util.Date.

Pressing Finish will generate the entities and will look like this.

package com.admfactory.entity;

import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;

/**
 * The persistent class for the user database table.
 * 
 */
@Entity
@Table(name = "user")
@NamedQuery(name = "UserEntity.findAll", query = "SELECT u FROM UserEntity u")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    private String email;

    private String name;

    private String password;

    private long updated;

    // uni-directional one-to-one association to UserDetailEntity
    @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @JoinColumn(name = "id")
    private UserDetailEntity userDetail;

    public UserEntity() {
    }

    public long getId() {
	return this.id;
    }

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

    public Date getCreated() {
	return this.created;
    }

    public void setCreated(Date created) {
	this.created = created;
    }

    public String getEmail() {
	return this.email;
    }

    public void setEmail(String email) {
	this.email = email;
    }

    public String getName() {
	return this.name;
    }

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

    public String getPassword() {
	return this.password;
    }

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

    public long getUpdated() {
	return this.updated;
    }

    public void setUpdated(long updated) {
	this.updated = updated;
    }

    public UserDetailEntity getUserDetail() {
	return this.userDetail;
    }

    public void setUserDetail(UserDetailEntity userDetail) {
	this.userDetail = userDetail;
    }

}

and

package com.admfactory.entity;

import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;

/**
 * The persistent class for the user_detail database table.
 * 
 */
@Entity
@Table(name = "user_detail")
@NamedQuery(name = "UserDetailEntity.findAll", query = "SELECT u FROM UserDetailEntity u")
public class UserDetailEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String address;

    private String city;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    @Column(name = "phone_number")
    private String phoneNumber;

    @Column(name = "postal_code")
    private String postalCode;

    @Temporal(TemporalType.TIMESTAMP)
    private Date updated;

    public UserDetailEntity() {
    }

    public long getId() {
	return this.id;
    }

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

    public String getAddress() {
	return this.address;
    }

    public void setAddress(String address) {
	this.address = address;
    }

    public String getCity() {
	return this.city;
    }

    public void setCity(String city) {
	this.city = city;
    }

    public Date getCreated() {
	return this.created;
    }

    public void setCreated(Date created) {
	this.created = created;
    }

    public String getPhoneNumber() {
	return this.phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
	this.phoneNumber = phoneNumber;
    }

    public String getPostalCode() {
	return this.postalCode;
    }

    public void setPostalCode(String postalCode) {
	this.postalCode = postalCode;
    }

    public Date getUpdated() {
	return this.updated;
    }

    public void setUpdated(Date updated) {
	this.updated = updated;
    }

}

Generate Entities using SuperMappedclass

When some fields are present in all of the tables then you can use a parent class to include all the common fields and all of the entities will extend that class.

The parent class need to be annotated with @MappedSuperclass. In our case both, tables contain id, created and updated column. Having this in mind here is the @MappedSuperclass class: BaseEntity.

package com.admfactory.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@MappedSuperclass
public class BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected long id;

    @Temporal(TemporalType.TIMESTAMP)
    protected Date created;

    @Temporal(TemporalType.TIMESTAMP)
    protected Date updated;

    public BaseEntity() {
    }

    public long getId() {
	return this.id;
    }

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

    public Date getCreated() {
	return this.created;
    }

    public void setCreated(Date created) {
	this.created = created;
    }

    public Date getUpdated() {
	return this.updated;
    }

    public void setUpdated(Date updated) {
	this.updated = updated;
    }
}

During the customisation step you need to select the superclass and also, remove the Serializable interface as BaseEntity class is already implementing the interface.

To avoid adding the columns that are already defined in the superclass you need to disable the property in the customisation step.

Now, UserEntity and UserDetailEntity will become simpler because a part is already defined in the super class.

Possible error

If you get the following error

Exception Description: Multiple writable mappings exist for the field [user.ID].  Only one may be defined as writable, all others must be specified read-only.

you need to add insertable=false, updatable=false on JoinColumn annotation from UserEntity class. The definition for the UserDetailEntity will become

// uni-directional one-to-one association to UserDetailEntity
@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
@JoinColumn(name = "id", insertable=false, updatable=false)
private UserDetailEntity userDetail;

Example

package com.admfactory;

import java.util.List;

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

import com.admfactory.entity.UserDetailEntity;
import com.admfactory.entity.UserEntity;

public class MainApp {

    public static final String PERSISTENCE_UNIT = "db";
    private static EntityManager em;

    /**
     * 
     * List to console all the users using NamedQuery
     *
     */
    public static void listAll() {
	Query queryAll = em.createNamedQuery("UserEntity.findAll");
	List<UserEntity> users = queryAll.getResultList();
	for (int i = 0; i < users.size(); i++) {
	    System.out.println("===========================");
	    UserEntity user = users.get(i);
	    System.out.println(user.getId() + " " + user.getName() + " " + user.getEmail() + " " + user.getPassword());

	    UserDetailEntity details = user.getUserDetail();
	    System.out.println(details.getId() + " " + details.getAddress() + " " + details.getCity() + " "
		    + details.getPhoneNumber() + " " + details.getPostalCode());

	    System.out.println("===========================");
	}
    }

    /**
     * 
     * insert a new user
     * 
     * @param name
     * @param email
     * @param password
     * @param address
     * @param city
     * @param phone
     * @param code
     */
    public static void insertUser(String name, String email, String password, String address, String city, String phone,
	    String code) {

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	UserEntity user = new UserEntity();
	user.setEmail(email);
	user.setName(name);
	user.setPassword(password);

	UserDetailEntity details = new UserDetailEntity();
	details.setAddress(address);
	details.setCity(city);
	details.setPhoneNumber(phone);
	details.setPostalCode(code);
	user.setUserDetail(details);
	em.persist(user);
	tx.commit();
    }

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

	/** insert some data */
	insertUser("User 1", "user1@admfactory.com", "aaa", "address 1", "city 1", "12345", "WS3 2SD");
	insertUser("User 2", "user2@admfactory.com", "bbb", "address 2", "city 2", "6789", "TY6 7PA");

	/** list some data */
	listAll();

	em.close();
    }

}

Output

Beside a big output from as debug information you can see the printout from the database.

...........
===========================
5 User 1 user1@admfactory.com aaa
5 address 1 city 1 12345 WS3 2SD
===========================
===========================
6 User 2 user2@admfactory.com bbb
6 address 2 city 2 6789 TY6 7PA
===========================
...........