JPA - Using @JoinTable in @OneToMany association

[Updated: Apr 21, 2017, Created: Apr 12, 2017]

@JoinTable annotation can be used in an association to customize the generated join table or to map the existing join table. In the following example, we will demonstrates how to use this annotation with @OneToMany association.

Example

@Entity
public class EntityA {
  @Id
  @GeneratedValue
  private int myIdA;
  @OneToMany
  @JoinTable(name = "MY_JOIN_TABLE",
          joinColumns = {@JoinColumn(name = "MY_ENTITY_A_FK")},
          inverseJoinColumns = {@JoinColumn(name = "MY_ENTITY_B_FK")}
  )
  private List<EntityB> entityBList;

  public List<EntityB> getEntityBList() {
      return entityBList;
  }

  public void setEntityBList(List<EntityB> entityBList) {
      this.entityBList = entityBList;
  }

  @Override
  public String toString() {
      return "EntityA{" +
              "myIdA=" + myIdA +
              ", entityBList=" + entityBList +
              '}';
  }
}
'joinColumns' and 'inverseJoinColumns' elements of @JoinTable

The element 'joinColumns' is used to specify foreign key column of the join table which references the source table (the owner of the association).

The element 'inverseJoinColumns' is used to specify foreign key column of the join table which references the target table (the inverse side of the association).

@Entity
public class EntityB {
  @Id
  @GeneratedValue
  private int myIdB;
  private String str;

  public String getStr() {
      return str;
  }

  public void setStr(String str) {
      this.str = str;
  }

  @Override
  public String toString() {
      return "EntityB{" +
              "myIdB=" + myIdB +
              ", str='" + str + '\'' +
              '}';
  }
}
public class ExampleMain {

  public static void main(String[] args) {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("test1");
      try {
          EntityManager em = emf.createEntityManager();
          nativeQuery(em, "SHOW TABLES");
          nativeQuery(em, "SHOW COLUMNS from EntityA");
          nativeQuery(em, "SHOW COLUMNS from EntityB");
          nativeQuery(em, "SHOW COLUMNS from MY_JOIN_TABLE");
          emf.close();
      } finally {
          emf.close();
      }
  }

  public static void nativeQuery(EntityManager em, String s) {
      System.out.printf("---------------------------%n'%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'
[ENTITYA, PUBLIC]
[ENTITYB, PUBLIC]
[MY_JOIN_TABLE, PUBLIC]
---------------------------
'SHOW COLUMNS from EntityA'
[MYIDA, INTEGER(10), NO, PRI, NULL]
---------------------------
'SHOW COLUMNS from EntityB'
[MYIDB, INTEGER(10), NO, PRI, NULL]
[STR, VARCHAR(255), YES, , NULL]
---------------------------
'SHOW COLUMNS from MY_JOIN_TABLE'
[MY_ENTITY_A_FK, INTEGER(10), NO, , NULL]
[MY_ENTITY_B_FK, INTEGER(10), NO, UNI, NULL]

Above output shows that specified names have been used for the join table generation, instead of the default ones.

Let's populate some data

public class ExampleMain2 {

  public static void main(String[] args) {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("test1");
      try {
          persistEntity(emf);
          nativeQueries(emf);
          loadEntityA(emf);
          loadEntityB(emf);
      } finally {
          emf.close();
      }
  }

  private static void nativeQueries(EntityManagerFactory emf) {
      System.out.println("-- native queries --");
      EntityManager em = emf.createEntityManager();
      ExampleMain.nativeQuery(em, "Select * from EntityA");
      ExampleMain.nativeQuery(em, "Select * from EntityB");
      ExampleMain.nativeQuery(em, "Select * from MY_JOIN_TABLE");
  }

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

      EntityB entityB = new EntityB();
      entityB.setStr("testStringB");

      EntityB entityB2 = new EntityB();
      entityB2.setStr("testStringB 2");

      EntityA entityA = new EntityA();
      entityA.setEntityBList(Arrays.asList(entityB, entityB2));

      em.getTransaction().begin();
      em.persist(entityA);
      em.persist(entityB);
      em.persist(entityB2);
      em.getTransaction().commit();

      em.close();
  }

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

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

Output

-- Persisting entities --
-- native queries --
---------------------------
'Select * from EntityA'
1
---------------------------
'Select * from EntityB'
[2, testStringB]
[3, testStringB 2]
---------------------------
'Select * from MY_JOIN_TABLE'
[1, 2]
[1, 3]
-- Loading EntityA --
EntityA{myIdA=1, entityBList=[EntityB{myIdB=2, str='testStringB'}, EntityB{myIdB=3, str='testStringB 2'}]}
-- Loading EntityB --
EntityB{myIdB=2, str='testStringB'}
EntityB{myIdB=3, str='testStringB 2'}

Example Project

Dependencies and Technologies Used :

  • h2 1.4.193: H2 Database Engine.
  • hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
  • JDK 1.8
  • Maven 3.3.9

Join Table With One To Many Example Select All Download
  • jpa-one-to-many-join-table
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF

See Also