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

Card Puncher Data Processing

About

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:

CREATE SEQUENCE "SEQ_GEN_IDENTITY" MINVALUE 1 MAXVALUE
  9999999999999999999999999999 INCREMENT BY 1 START WITH 1;

JPA

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.io.Serializable;
import java.util.ArrayList;
import java.util.List;

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

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

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

    // The Many-to-May Column is declared here
    @ManyToMany
    @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) {
        this.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.
        getHelloCategories().add(helloCategory);

    }

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

Category Table

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


@Entity
@Table(name="CAT")
public class HelloCategory implements Serializable {

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

    public HelloCategory() {
    }

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

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
    
    @Override
    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="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_1_0.xsd">
    <persistence-unit name="PersistenceUnitName" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>HelloWorld</class>
        <class>HelloCategory</class>
    </persistence-unit>
</persistence>

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.JDBC_DRIVER,"oracle.jdbc.OracleDriver");
        props.put(PersistenceUnitProperties.JDBC_URL,"jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local");
        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.setId("1");
        aNormalHelloWorld.setDescription("Hello Nico !");
        // The normal Hello Categorie
        HelloCategory aNormalHelloCategory = new HelloCategory();
        aNormalHelloCategory.setTitle("A normal Hello");
        aNormalHelloWorld.add(aNormalHelloCategory);

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

        // Persistence
        em.getTransaction().begin();
        em.merge(aNormalHelloWorld);
        em.merge(aBigHelloWorld);
        em.getTransaction().commit();
        
        // Retrieve
        // Hello World whose primary key is 1
        HelloWorld helloWorld = em.find(HelloWorld.class, "1");
        System.out.println(helloWorld);
        
        em.close();
        emf.close();

    }

}

Output

[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(
	platform=>Oracle11Platform
	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 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
	Driver: Oracle JDBC driver  Version: 11.1.0.7.0-Production
[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