Make delicious recipes!


Map-type fields


In this post, we will examine how to store ma-type fields in an entity using Hibernate.
Map-type fields will be of two types:
Map<Integer, Entity>
Map<Entity, Entity>


Here is the directory structure:
./pom.xml
./src/main/java/com/prismoskills/hibernate/hierarchy/HibernateFieldsTest.java
./src/main/java/com/prismoskills/hibernate/hierarchy/pojos/fields/BaseEntity.java
./src/main/java/com/prismoskills/hibernate/hierarchy/pojos/fields/Company.java
./src/main/java/com/prismoskills/hibernate/hierarchy/pojos/fields/Employee.java
./src/main/java/com/prismoskills/hibernate/hierarchy/pojos/fields/Job.java
./src/main/java/com/prismoskills/hibernate/hierarchy/pojos/fields/Manager.java
./src/main/resources/META-INF/persistence.xml



src/main/resources/META-INF/persistence.xml:

<persistence 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"
        version="2.0">
        
    <persistence-unit name="com.prismoskills.hibernate">
      <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
      
      <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
        <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@//localhost:1522/XE"/>
        <property name="javax.persistence.jdbc.user" value="system"/>
        <property name="javax.persistence.jdbc.password" value="password"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.use_sql_comments" value="true"/>
      </properties>
    </persistence-unit>
</persistence>




src/main/resources/log4j.properties
# Root logger option
log4j.rootLogger= INFO , stdout
 
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout



pom.xml: hibernate-entitymanager dependency needs to be added for JPA compliance.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.prismoskills.hibernate</groupId>
  <artifactId>persistence</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>persistence</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.3.0.CR2</version>
    </dependency>
            
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0</version>
    </dependency>
    
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
            
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>4.3.0.CR2</version>
    </dependency>
            
  </dependencies>

 
  <build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.1</version>
        <configuration>
            <transformers>
                <transformer
                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                    <manifestEntries>
                        <Main-Class>com.prismoskills.hibernate.hierarchy.PersistenceExample</Main-Class>
                    </manifestEntries>
                </transformer>
            </transformers>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    </plugins>
  </build>
  
</project>




SQL:
/* Drop existing tables */
Drop table JOB;
Drop table COMPANY;
Drop table MANAGER;
Drop table EMPLOYEE;

/* Create new tables */

/* Employee */
CREATE TABLE EMPLOYEE
(
  "ID"                 NUMBER NOT NULL ENABLE,
  "NAME"               VARCHAR2(64 BYTE), 
  CONSTRAINT "PK_EMPLOYEE_ID"     PRIMARY KEY ("ID")
);

/* Manager */
CREATE TABLE MANAGER
(
  "ID"                 NUMBER NOT NULL ENABLE,
  "NAME"               VARCHAR2(64 BYTE),
  CONSTRAINT "PK_MANAGER_ID" PRIMARY KEY ("ID")
);

/* Company */
CREATE TABLE COMPANY
(
  "ID"                 NUMBER NOT NULL ENABLE,
  "NAME"               VARCHAR2(64 BYTE),
  "EMPLOYEE_ID"        NUMBER,
  "MANAGER_ID"         NUMBER,
  CONSTRAINT "PK_COMPANY_ID" PRIMARY KEY ("ID"),
  FOREIGN KEY (MANAGER_ID) references MANAGER(ID),
  FOREIGN KEY (EMPLOYEE_ID) references EMPLOYEE(ID)
);

/* Job */
CREATE TABLE JOB
(
  "ID"                   NUMBER NOT NULL ENABLE,
  "DESIGNATION"          VARCHAR2(64 BYTE),
  "EMPLOYEE_ID"          NUMBER,
  CONSTRAINT "PK_JOB_ID" PRIMARY KEY ("ID"),
  FOREIGN KEY (EMPLOYEE_ID) references EMPLOYEE(ID)
);



HibernateFieldsTest: This is the class having main().
package com.prismoskills.hibernate.hierarchy;

import java.util.HashMap;
import java.util.Map;

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

import com.prismoskills.hibernate.hierarchy.pojos.fields.Company;
import com.prismoskills.hibernate.hierarchy.pojos.fields.Employee;
import com.prismoskills.hibernate.hierarchy.pojos.fields.Job;
import com.prismoskills.hibernate.hierarchy.pojos.fields.Manager;

public class HibernateFieldsTest
{
    public static void main(String args[])
    {
        final Employee employee = new Employee("Michael");

        // Add map with primitive key Integer
        Job job1 = new Job("Software Engineer", employee);
        Job job2 = new Job("Senior S/W Engineer", employee);
        Map<Integer, Job> jobs = new HashMap<Integer, Job>();
        jobs.put(job1.getId(), job1);
        //jobs.put(job2.getId(), job2);
        employee.setJobs(jobs);

        // Add map with entity key Manager
        Manager john = new Manager("John");
        Company apple = new Company("Apple");
        apple.setManager(john);
        apple.setEngineer(employee);

        Manager rambo = new Manager("Rambo");
        Company google = new Company("Google");
        google.setManager(rambo);
        google.setEngineer(employee);

        Map<Manager, Company> companyMap = new HashMap<Manager, Company>();
        companyMap.put(john, apple);
        //companyMap.put(rambo, google);
        employee.setCompanyMap(companyMap);

        EntityManagerFactory emf = null;
        EntityManager em = null;
        EntityTransaction tx = null;
        try
        {
            emf = Persistence.createEntityManagerFactory("com.prismoskills.hibernate");
            em = emf.createEntityManager();

            tx = em.getTransaction();
            tx.begin();
            //em.merge(employee);
            em.persist(employee);
            em.flush();
            tx.commit();
            em.close();

            System.out.println ("Finished save. Now reading.");
            em = emf.createEntityManager();
            tx = em.getTransaction();
            tx.begin();
            Employee result = em.find(Employee.class, employee.getId());
            System.out.println ("Read " + result.getName());

            em.remove(result);
            tx.commit();
            em.close(); em = null;
            emf.close(); emf = null;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            if (tx!=null)
                tx.rollback();
            System.exit(1);
        }
        finally
        {
            if (em != null)
                em.close();
            if (emf != null)
                emf.close();
        }
        System.out.println ("Finished execution");
    }
}


BaseEntity: This base class auto-generates a primary-key "ID" for all the entities that derive from it.
package com.prismoskills.hibernate.hierarchy.pojos.fields;

import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public class BaseEntity
{
    @Id
    Integer id;

    public BaseEntity()
    {
        getId();
    }

    public Integer getId()
    {
        if (id == null)
        {
            id = (int)System.currentTimeMillis();
        }
        return id;
    }

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



Manager: Nothing special in this class. Just a POJO
package com.prismoskills.hibernate.hierarchy.pojos.fields;

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "MANAGER")
public class Manager extends BaseEntity
{
    String name;

    public Manager()
    {
    }

    public Manager(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }

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



Job: Many jobs can have a single Employee. Or in other words, one Employee can have many jobs in his career.
package com.prismoskills.hibernate.hierarchy.pojos.fields;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "JOB")
public class Job extends BaseEntity
{
    String designation;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "EMPLOYEE_ID", nullable = false)
    Employee employee;

    public Job(String designation, Employee employee)
    {
        this.designation = designation;
        this.employee = employee;
    }

    public Job()
    {
        super();
    }

    public String getDesignation() 
    {
        return designation;
    }

    public void setDesignation(String designation)
    {
        this.designation = designation;
    }

    public Employee getEmployee()
    {
        return employee;
    }

    public void setEmployee(Employee employee)
    {
        this.employee = employee;
    }
}



Employee: Most interesting class.
One employee can have many jobs. Hence a map of ID-vs-Job.
A list could also have sufficed here but we wanted to show a slightly complex case.

One employee can also have one manager per company.
Hence a map of Manager-vs-Company.
package com.prismoskills.hibernate.hierarchy.pojos.fields;

import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.MapKey;
import javax.persistence.MapKeyJoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "EMPLOYEE")
public class Employee extends BaseEntity
{
    String name;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "employee")
    @MapKey
    Map<Integer, Job> jobs;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "engineer")
    @MapKey
    @MapKeyJoinColumn(name = "MANAGER_ID")
    Map<Manager, Company> companyMap;

    public Employee()
    {
        super();
    }

    public Employee(String name)
    {
        this.name = name;
    }

    public Map<Integer, Job> getJobs()
    {
        return jobs;
    }

    public void setJobs(Map<Integer, Job> jobs)
    {
        this.jobs = jobs;
    }

    public Map<Manager, Company> getCompanyMap()
    {
        return companyMap;
    }

    public void setCompanyMap(Map<Manager, Company> companyMap)
    {
        this.companyMap = companyMap;
    }

    public String getName()
    {
        return name;
    }

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



Company:
package com.prismoskills.hibernate.hierarchy.pojos.fields;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = "COMPANY")
public class Company extends BaseEntity
{
    String name;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "EMPLOYEE_ID")
    Employee engineer;

    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "MANAGER_ID", nullable = false)
    Manager manager;

    public Company()
    {
        super();
    }

    public Company(String name)
    {
        super();
        this.name = name;
    }

    public String getName()
    {
        return name;
    }

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

    public Employee getEngineer()
    {
        return engineer;
    }

    public void setEngineer(Employee engineer)
    {
        this.engineer = engineer;
    }

    public Manager getManager()
    {
        return manager;
    }

    public void setManager(Manager manager)
    {
        this.manager = manager;
    }

    @Override
    public String toString()
    {
        return "Company [name=" + name + "]";
    }
}



Output

insert into EMPLOYEE 
    (name, id) values (?, ?)

insert into MANAGER 
    (name, id) values (?, ?)

insert into COMPANY 
    (EMPLOYEE_ID, MANAGER_ID, name, id) values (?, ?, ?, ?)

insert into JOB 
    (designation, EMPLOYEE_ID, id) values (?, ?, ?)



// Finished save. Now reading.

    SELECT
        emp.id as id1_3_0,
        emp.name as name2_3_0,

        cmap.EMPLOYEE_ID as EMPLOYEE_ID3_3_1,
        cmap.id as id1_1_1,
        cmap.id as formula0_1,
        cmap.id as id1_1_2,
        cmap.EMPLOYEE_ID as EMPLOYEE_ID3_1_2,
        cmap.MANAGER_ID as MANAGER_ID4_1_2,
        cmap.name as name2_1_2,

        mgr.id as id1_5_3,
        mgr.name as name2_5_3,

        jobs.EMPLOYEE_ID as EMPLOYEE_ID3_3_4,
        jobs.id as id1_4_4,
        jobs.id as formula1_4,
        jobs.id as id1_4_5,
        jobs.designation as designation2_4_5,
        jobs.EMPLOYEE_ID as EMPLOYEE_ID3_4_5

    from
        EMPLOYEE emp 
    left outer join
        COMPANY cmap 
            on emp.id = cmap.EMPLOYEE_ID 
    left outer join
        MANAGER mgr 
            on cmap.MANAGER_ID = mgr.id 
    left outer join
        JOB jobs 
            on emp.id = jobs.EMPLOYEE_ID 
    where
        emp.id = ?



Delete from COMPANY where id=?
Delete from MANAGER where id=?
Delete from JOB where id=?
Delete from EMPLOYEE where id=?

Insertion Order

First of all, Hibernate inserts into Employee and Manager
tables because they do not have any foreign keys.
Then it inserts data into Company and Job tables because now
it has foreign keys for those tables.



Select Query

Observe the select query. For efficiency, Hibernate
loads all the data in one go. This is because of the
EAGER annotation in the above POJO classes.

If the EAGER annotation was not there, then Hibernate
would do lazy-loading by default and only the foreign-keys
would be loaded without joins. Something like this:
select e.id, e.name
from EMPLOYEE e 
where e.id=?






Delete Queries

Deletion order is somewhat opposite to the insertion order.
This is again to mitigate the foreign-key constraints.

Hibernate first deletes the entry which has a foreign-key field.
If it were to delete the child table first, then database would
given an error for invalid foreign key in the parent table.











Like us on Facebook to remain in touch
with the latest in technology and tutorials!


Got a thought to share or found a
bug in the code?
We'd love to hear from you:

Name:
Email: (Your email is not shared with anybody)
Comment:

Facebook comments:

Site Owner: Sachin Goyal