JPA - Bidirectional OneToMany/ManyToOne Example

[Updated: May 31, 2017, Created: Apr 18, 2017]
A quick overview of bidirectional one-to-many/many-to-one relationship in JPA
  • In bidirectional one-to-many/many-to-one relationship, the target side has a reference back to the source entity as well.
  • The annotation @OneToMany is used on the side which has the collection reference.
  • The annotation @ManyToOne is used on the side which has the single-valued back reference.
  • We must use 'mappedBy' element of the @OneToMany annotations to specify that the corresponding table will be the parent table. In other words the other side (which has @ManyToOne) will have the foreign-key table (child table).
  • The value of 'mappedBy' element should be the name of the reference variable used in the other class's back reference.
  • The side which has 'mappedBy' specified, will be the target entity of the relationship and corresponding table will be the parent of the relationship .
  • The side which doesn't have 'mappedBy' element will be the source (owner) and the corresponding table will be the child of the relationship, i.e. it will have the foreign key column.
  • On the owner side, we can also use @JoinColumn, whose one of the purposes is to specify a foreign key column name instead of relying on the default name.

Example

@Entity
public class EntityA {
  @Id
  @GeneratedValue
  private int myIdA;
  private String strA;
  @OneToMany(mappedBy = "refEntityA")
  private List<EntityB> entityBList;
    .............
}
@Entity
public class EntityB {
  @Id
  @GeneratedValue
  private int myIdB;
  private String strB;
  @ManyToOne
  private EntityA refEntityA;
    .............
}
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");
          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]
-----------------------------
'SHOW COLUMNS from EntityA'
[MYIDA, INTEGER(10), NO, PRI, NULL]
[STRA, VARCHAR(255), YES, , NULL]
-----------------------------
'SHOW COLUMNS from EntityB'
[MYIDB, INTEGER(10), NO, PRI, NULL]
[STRB, VARCHAR(255), YES, , NULL]
[REFENTITYA_MYIDA, INTEGER(10), YES, , NULL]

H2 database SHOW statements

Following is a quick overview of the relationship:

Persisting and loading entities

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");
  }

  private static void persistEntity(EntityManagerFactory emf) {
      EntityManager em = emf.createEntityManager();

      EntityB entityB1 = new EntityB();
      entityB1.setStrB("testStringB");

      EntityB entityB2 = new EntityB();
      entityB2.setStrB("testStringB2");

      EntityA entityA = new EntityA();
      entityA.setStrA("testStringA");
      entityA.setEntityBList(Arrays.asList(entityB1, entityB2));

      entityB1.setRefEntityA(entityA);
      entityB2.setRefEntityA(entityA);

      System.out.println("-- persisting entities --");
      System.out.printf(" %s%n entityA#entityBList: %s%n", entityA, entityA.getEntityBList());
      System.out.printf(" %s%n entityB1#refEntityA: %s%n", entityB1, entityB1.getRefEntityA());
      System.out.printf(" %s%n entityB2#refEntityA: %s%n", entityB2, entityB2.getRefEntityA());

      em.getTransaction().begin();
      em.persist(entityA);
      em.persist(entityB1);
      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(e -> System.out.printf(" %s%n entityA#entityBList: %s%n", e, e.getEntityBList()));
      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(e -> System.out.printf(" %s%n entityB#refEntityA: %s%n", e, e.getRefEntityA()));
      em.close();
  }
}

Output

-- persisting entities --
EntityA{myIdA=0, strA='testStringA'}
entityA#entityBList: [EntityB{myIdB=0, strB='testStringB'}, EntityB{myIdB=0, strB='testStringB2'}]
EntityB{myIdB=0, strB='testStringB'}
entityB1#refEntityA: EntityA{myIdA=0, strA='testStringA'}
EntityB{myIdB=0, strB='testStringB2'}
entityB2#refEntityA: EntityA{myIdA=0, strA='testStringA'}
-- native queries --
-----------------------------
'Select * from EntityA'
[1, testStringA]
-----------------------------
'Select * from EntityB'
[2, testStringB, 1]
[3, testStringB2, 1]
-- loading EntityA --
EntityA{myIdA=1, strA='testStringA'}
entityA#entityBList: [EntityB{myIdB=2, strB='testStringB'}, EntityB{myIdB=3, strB='testStringB2'}]
-- Loading EntityB --
EntityB{myIdB=2, strB='testStringB'}
entityB#refEntityA: EntityA{myIdA=1, strA='testStringA'}
EntityB{myIdB=3, strB='testStringB2'}
entityB#refEntityA: EntityA{myIdA=1, strA='testStringA'}

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

Bidirectional One To Many Example Select All Download
  • jpa-bidirectional-one-to-many-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF

See Also