JPA - How to model a @Many-to-Many Relationship ?

Card Puncher Data Processing


How to model a many-to-many relationship in JPA.

Data Model

(Oracle) Database

One Hello can have several Category and One Category can have several Hello.

Hello Data Model Many To Many

The Ddl File: Ddl File

One sequence:

  9999999999999999999999999999 INCREMENT BY 1 START WITH 1;


Hello Table with the HelloCategory Table

The HelloWorld entity with an object-relational mapping annotation that models the HELLO and HELLOCATEGORIE tables.

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Table(name = "HELLO")
public class HelloWorld implements Serializable {

    @Column(name = "ID", unique = true, nullable = false, updatable=false)
    private String id;

    @Column(name = "DESCRIPTION")
    private String Description;

    // The Many-to-May Column is declared here
    @JoinTable(name = "HELLOCATEGORIE", joinColumns = @JoinColumn(name = "ID_HELLO"), inverseJoinColumns = @JoinColumn(name = "ID_CAT"))
    private List<HelloCategory> helloCategories = new ArrayList<HelloCategory>();

    public String getId() {
        return id;

    public void setId(String id) { = id;

    public String getDescription() {
        return Description;

    public void setDescription(String description) {
        Description = description;

    public void add(HelloCategory helloCategory) {
        //To change body of created methods use File | Settings | File Templates.


    public List<HelloCategory> getHelloCategories() {
        return helloCategories;
    public String toString() {
        return "HelloWorld{" +
                "id='" + id + '\'' +
                ", Description='" + Description + '\'' +
                ", helloCategories=" + helloCategories +

Category Table

import javax.persistence.*;

public class HelloCategory implements Serializable {

    @Column(name = "ID_CAT")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(name = "CAT_NAME")
    private String title;

    public HelloCategory() {

    public long getId() {

    public void setId(long id) { = id;

    public String getTitle() {
        return title;

    public void setTitle(String title) {
        this.title = title;
    public String toString() {
        return "HelloCategory{" +
                "id=" + id +
                ", title='" + title + '\'' +

Persistence Unit Configuration

The persistence unit (PersistenceUnitName) in the persistence.xml file that defines:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns=""
    <persistence-unit name="PersistenceUnitName" transaction-type="RESOURCE_LOCAL">

Main Code

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.TargetDatabase;
import org.eclipse.persistence.logging.SessionLog;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] args) {

        Map props = new HashMap();

        props.put(PersistenceUnitProperties.JDBC_USER, "sh");
        props.put(PersistenceUnitProperties.JDBC_PASSWORD, "sh");
        props.put(PersistenceUnitProperties.TARGET_DATABASE, TargetDatabase.Oracle11);
        props.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINE_LABEL);

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnitName", props);

        EntityManager em = emf.createEntityManager();

        // A normal Hello World Construction
        // The normal Hello World
        HelloWorld aNormalHelloWorld = new HelloWorld();
        aNormalHelloWorld.setDescription("Hello Nico !");
        // The normal Hello Categorie
        HelloCategory aNormalHelloCategory = new HelloCategory();
        aNormalHelloCategory.setTitle("A normal Hello");

        // A Big Hello World Construction
        // The big Hello
        HelloWorld aBigHelloWorld = new HelloWorld();
        aBigHelloWorld.setDescription("HELLO NICO !");
        // The big Category
        HelloCategory aBigHelloCategory = new HelloCategory();
        aBigHelloCategory.setTitle("A BIG Hello");

        // Persistence
        // Retrieve
        // Hello World whose primary key is 1
        HelloWorld helloWorld = em.find(HelloWorld.class, "1");




[EL Config]: metadata: 2013-12-21 17:22:38.189--ServerSession(1595026786)--Thread(Thread[main,5,main])--The access type for the persistent class [class HelloCategory] is set to [FIELD].
[EL Config]: metadata: 2013-12-21 17:22:38.22--ServerSession(1595026786)--Thread(Thread[main,5,main])--The access type for the persistent class [class HelloWorld] is set to [FIELD].
[EL Config]: metadata: 2013-12-21 17:22:38.234--ServerSession(1595026786)--Thread(Thread[main,5,main])--The target entity (reference) class for the many to many mapping element [field helloCategories] is being defaulted to: class HelloCategory.
[EL Config]: metadata: 2013-12-21 17:22:38.235--ServerSession(1595026786)--Thread(Thread[main,5,main])--The alias name for the entity class [class HelloCategory] is being defaulted to: HelloCategory.
[EL Config]: metadata: 2013-12-21 17:22:38.267--ServerSession(1595026786)--Thread(Thread[main,5,main])--The alias name for the entity class [class HelloWorld] is being defaulted to: HelloWorld.
[EL Config]: metadata: 2013-12-21 17:22:38.294--ServerSession(1595026786)--Thread(Thread[main,5,main])--The source primary key column name for the many to many mapping [field helloCategories] is being defaulted to: ID.
[EL Config]: metadata: 2013-12-21 17:22:38.295--ServerSession(1595026786)--Thread(Thread[main,5,main])--The target primary key column name for the many to many mapping [field helloCategories] is being defaulted to: ID_CAT.
[EL Info]: 2013-12-21 17:22:38.962--ServerSession(1595026786)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20131113-a7346c6
[EL Config]: connection: 2013-12-21 17:22:38.971--ServerSession(1595026786)--Connection(1297590473)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	user name=> "sh"
	datasource URL=> "jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local"
[EL Config]: connection: 2013-12-21 17:22:39.503--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--Connected: jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local
	User: SH
	Database: Oracle  Version: Oracle Database 12c Enterprise Edition Release - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
	Driver: Oracle JDBC driver  Version:
[EL Info]: connection: 2013-12-21 17:22:39.576--ServerSession(1595026786)--Thread(Thread[main,5,main])--file:/D:/svn_obiee-utility-plus/target/classes/_PersistenceUnitName_url=jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local_user=sh login successful
[EL Fine]: sql: 2013-12-21 17:22:39.64--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT ID, DESCRIPTION FROM HELLO WHERE (ID = ?)
	bind => [1]
[EL Fine]: sql: 2013-12-21 17:22:39.775--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT t1.ID_CAT, t1.CAT_NAME FROM HELLOCATEGORIE t0, CAT t1 WHERE ((t0.ID_HELLO = ?) AND (t1.ID_CAT = t0.ID_CAT))
	bind => [1]
[EL Fine]: sql: 2013-12-21 17:22:39.781--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT SEQ_GEN_IDENTITY.NEXTVAL FROM DUAL
[EL Fine]: sql: 2013-12-21 17:22:39.783--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT ID, DESCRIPTION FROM HELLO WHERE (ID = ?)
	bind => [2]
[EL Fine]: sql: 2013-12-21 17:22:39.785--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT t1.ID_CAT, t1.CAT_NAME FROM HELLOCATEGORIE t0, CAT t1 WHERE ((t0.ID_HELLO = ?) AND (t1.ID_CAT = t0.ID_CAT))
	bind => [2]
[EL Fine]: sql: 2013-12-21 17:22:39.787--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--SELECT SEQ_GEN_IDENTITY.NEXTVAL FROM DUAL
[EL Fine]: sql: 2013-12-21 17:22:39.796--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--INSERT INTO CAT (ID_CAT, CAT_NAME) VALUES (?, ?)
	bind => [34, A BIG Hello]
[EL Fine]: sql: 2013-12-21 17:22:39.798--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--INSERT INTO CAT (ID_CAT, CAT_NAME) VALUES (?, ?)
	bind => [33, A normal Hello]
[EL Fine]: sql: 2013-12-21 17:22:39.801--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--DELETE FROM HELLOCATEGORIE WHERE ((ID_CAT = ?) AND (ID_HELLO = ?))
	bind => [31, 1]
[EL Fine]: sql: 2013-12-21 17:22:39.804--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--INSERT INTO HELLOCATEGORIE (ID_CAT, ID_HELLO) VALUES (?, ?)
	bind => [33, 1]
[EL Fine]: sql: 2013-12-21 17:22:39.805--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--DELETE FROM HELLOCATEGORIE WHERE ((ID_CAT = ?) AND (ID_HELLO = ?))
	bind => [32, 2]
[EL Fine]: sql: 2013-12-21 17:22:39.807--ClientSession(1269220824)--Connection(3559837)--Thread(Thread[main,5,main])--INSERT INTO HELLOCATEGORIE (ID_CAT, ID_HELLO) VALUES (?, ?)
	bind => [34, 2]

System Output

HelloWorld{id='1', Description='Hello Nico !', helloCategories={[HelloCategory{id=33, title='A normal Hello'}]}}

[EL Config]: connection: 2013-12-21 17:22:39.819--ServerSession(1595026786)--Connection(3559837)--Thread(Thread[main,5,main])--disconnect
[EL Info]: connection: 2013-12-21 17:22:39.82--ServerSession(1595026786)--Thread(Thread[main,5,main])--file:/D:/svn_obiee-utility-plus/target/classes/_PersistenceUnitName_url=jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local_user=sh logout successful
[EL Config]: connection: 2013-12-21 17:22:39.821--ServerSession(1595026786)--Connection(1297590473)--Thread(Thread[main,5,main])--disconnect

Discover More
Card Puncher Data Processing
JPA - (Association) Fetch

The fetch attribute is a enum that specifies whether to load the field's persisted data: before the entity object is returned by the persistence provider (FetchType.EAGER) or later, when the property...
Jpa Mapping Method
JPA - Entity Annotations

A key feature of EJB 3.0 and JPA is the ability to create entities that contain object-relational mappings by using (metadata) annotations rather than deployment descriptors (orm.xml) as in earlier versions....
Card Puncher Data Processing
JPA - Getting Started - Hello World

A simple JPA implementation that insert an “Hello World” string in a HELLO table in a relational database. This example uses the JPA reference implementation: against an Oracle Database. Maven...
Card Puncher Data Processing
JPA - Relationship

JPA - Relationship

Share this page:
Follow us:
Task Runner