Close

JPA - OneToMany foreign key mapping strategy for persisting Map with basic type keys and entity values

For java.util.Map entity values, applying foreign key mapping strategy is similar to other collection mapping, where we need to use @JoinColumn on @OneToMany side. Instead of an intermediate join table, a foreign-key column is used in the value entity table.

Example

@Entity
public class Employee {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  @OneToMany
  @JoinColumn(name = "EMPLOYEE_FK")
  @MapKeyColumn(name = "TASK_DATE", nullable = true)
  private Map<Date, Task> tasks;
    .............
}
@Entity
public class Task {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  private String description;
    .............
}
public class ExampleMain {

  public static void main(String[] args) {
      EntityManagerFactory emf =
              Persistence.createEntityManagerFactory("example-unit");
      try {
          EntityManager em = emf.createEntityManager();
          nativeQuery(em, "SHOW TABLES");
          nativeQuery(em, "SHOW COLUMNS from EMPLOYEE");
          nativeQuery(em, "SHOW COLUMNS from TASK");
          nativeQuery(em, "SHOW COLUMNS from EMPLOYEE_TASK");
      } finally {
          emf.close();
      }
  }

  public static void nativeQuery(EntityManager em, String s) {
      System.out.printf("'%s'%n", s);
      Query query = em.createNativeQuery(s);
      List list = query.getResultList();
      for (Object o : list) {
          if (o instanceof Object[]) {
              System.out.println(Arrays.toString((Object[]) o));
          } else {
              System.out.println(o);
          }
      }
  }
}

Output

'SHOW TABLES'
[EMPLOYEE, PUBLIC]
[TASK, PUBLIC]
'SHOW COLUMNS from EMPLOYEE'
[ID, BIGINT(19), NO, PRI, NULL]
[NAME, VARCHAR(255), YES, , NULL]
'SHOW COLUMNS from TASK'
[ID, BIGINT(19), NO, PRI, NULL]
[DESCRIPTION, VARCHAR(255), YES, , NULL]
[NAME, VARCHAR(255), YES, , NULL]
[EMPLOYEE_FK, BIGINT(19), YES, , NULL]
[TASK_DATE, TIMESTAMP(23), NO, , NULL]
'SHOW COLUMNS from EMPLOYEE_TASK'

Persisting and loading data

public class ExampleMain2 {

  public static void main(String[] args) throws Exception {
      EntityManagerFactory emf =
              Persistence.createEntityManagerFactory("example-unit");
      try {
          persistEntity(emf);
          runNativeQueries(emf);
          loadEntity(emf);
      } finally {
          emf.close();
      }
  }

  private static void persistEntity(EntityManagerFactory emf) throws Exception {
      System.out.println("-- Persisting entities --");
      EntityManager em = emf.createEntityManager();

      Employee e1 = new Employee();
      e1.setName("employee name 1");

      Task task1 = new Task();
      task1.setName("task 1");
      task1.setDescription("task 1 desc");

      SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yy");
      Task task2 = new Task();
      task2.setName("task 2");
      task2.setDescription("task 2 desc");

      e1.addTask(sdf.parse("15-01-17"), task1);
      e1.addTask(sdf.parse("20-01-17"), task2);
      System.out.println(e1);

      Employee e2 = new Employee();
      e2.setName("employee name 2");

      Task task3 = new Task();
      task3.setName("task 3");
      task3.setDescription("task 3 desc");

      e2.addTask(sdf.parse("02-05-2017"), task3);
      System.out.println(e2);

      em.getTransaction().begin();
      em.persist(task1);
      em.persist(task2);
      em.persist(task3);
      em.persist(e1);
      em.persist(e2);
      em.getTransaction().commit();
      em.close();
  }

  private static void runNativeQueries(EntityManagerFactory emf) {
      System.out.println("-- Native queries --");
      EntityManager em = emf.createEntityManager();
      ExampleMain.nativeQuery(em, "Select * from Employee");
      ExampleMain.nativeQuery(em, "Select * from Task");
  }

  private static void loadEntity(EntityManagerFactory emf) {
      System.out.println("-- Loading entities --");
      EntityManager em = emf.createEntityManager();
      List<Employee> entityAList = em.createQuery("Select t from Employee t")
                                     .getResultList();
      entityAList.forEach(System.out::println);
      em.close();
  }
}

Output

-- Persisting entities --
Employee{id=0, name='employee name 1', tasks={Thu Mar 01 00:00:00 CST 2018=Task{id=0, name='task 1', description='task 1 desc'}, Wed Aug 01 00:00:00 CDT 2018=Task{id=0, name='task 2', description='task 2 desc'}}}
Employee{id=0, name='employee name 2', tasks={Sun Feb 05 00:00:00 CST 2017=Task{id=0, name='task 3', description='task 3 desc'}}}
-- Native queries --
'Select * from Employee'
[4, employee name 1]
[5, employee name 2]
'Select * from Task'
[1, task 1 desc, task 1, 4, 2018-03-01 00:00:00.0]
[2, task 2 desc, task 2, 4, 2018-08-01 00:00:00.0]
[3, task 3 desc, task 3, 5, 2017-02-05 00:00:00.0]
-- Loading entities --
Employee{id=4, name='employee name 1', tasks={2018-03-01 00:00:00.0=Task{id=1, name='task 1', description='task 1 desc'}, 2018-08-01 00:00:00.0=Task{id=2, name='task 2', description='task 2 desc'}}}
Employee{id=5, name='employee name 2', tasks={2017-02-05 00:00:00.0=Task{id=3, name='task 3', description='task 3 desc'}}}

Example Project

Dependencies and Technologies Used:

  • h2 1.4.195: H2 Database Engine.
  • hibernate-core 5.2.10.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • JDK 1.8
  • Maven 3.3.9

map-with-entity-values-foreign-key-strategy Select All Download
  • map-with-entity-values-foreign-key-strategy
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • Employee.java
          • resources
            • META-INF

    See Also