- As compare to unidirectional many-to-many,in bidirectional many-to-many association, both sides will have collections, referencing each other.
- We have to use @ManyToMany annotation in both entities, on the corresponding collections.
- From database perceptive there will be no difference, there will still be the same join table with the same columns.
- Note that unidirectional vs bidirectional is never a concern of database tables, as we can always use queries in both directions without any additional hint or meta-data, whereas, in JPA world we need additional meta-data to tell the underlying ORM to generate additional reverse queries.
Example
@Entity
public class EntityA {
@Id
@GeneratedValue
private int myIdA;
@ManyToMany
private List<EntityB> entityBList;
private String strA;
.............
}
@Entity
public class EntityB {
@Id
@GeneratedValue
private int myIdB;
@ManyToMany
private List<EntityA> entityAList;
private String strB;
.............
}
public class ExampleMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
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 ENTITYA_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] [ENTITYA_ENTITYB, PUBLIC] [ENTITYB, PUBLIC] [ENTITYB_ENTITYA, 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] --------------------------- 'SHOW COLUMNS from ENTITYA_ENTITYB' [ENTITYA_MYIDA, INTEGER(10), NO, , NULL] [ENTITYBLIST_MYIDB, INTEGER(10), NO, , NULL]
A quick overview of the relationship:
Persisting and loading entities
public class ExampleMain2 {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
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 ENTITYA_ENTITYB");
}
private static void persistEntity(EntityManagerFactory emf) {
System.out.println("-- Persisting entities --");
EntityManager em = emf.createEntityManager();
EntityB entityB = new EntityB();
entityB.setStrB("testStringB");
EntityB entityB2 = new EntityB();
entityB2.setStrB("testStringB2");
EntityA entityA = new EntityA();
entityA.setStrA("testStringA");
entityA.setEntityBList(Arrays.asList(entityB, entityB2, entityB));
EntityA entityA2 = new EntityA();
entityA2.setStrA("testStringA2");
entityA2.setEntityBList(Arrays.asList(entityB, entityB2));
entityB.setEntityAList(Arrays.asList(entityA, entityA2));
entityB2.setEntityAList(Arrays.asList(entityA, entityA2));
em.getTransaction().begin();
em.persist(entityA);
em.persist(entityA2);
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((x) -> {
System.out.println(x);
System.out.printf("EntityA#entityBList: %s%n", x.getEntityAList());
});
em.close();
}
} Output-- Persisting entities -- --- native queries --------------------------- 'Select * from EntityA' [1, testStringA] [2, testStringA2] --------------------------- 'Select * from EntityB' [3, testStringB] [4, testStringB2] --------------------------- 'Select * from ENTITYA_ENTITYB' [1, 3] [1, 4] [1, 3] [2, 3] [2, 4] -- Loading EntityA -- EntityA{myIdA=1, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}, EntityB{myIdB=3, strB='testStringB'}]} EntityA{myIdA=2, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}]} -- Loading EntityB -- EntityB{myIdB=3, strB='testStringB'} EntityA#entityBList: [EntityA{myIdA=1, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}, EntityB{myIdB=3, strB='testStringB'}]}, EntityA{myIdA=2, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}]}] EntityB{myIdB=4, strB='testStringB2'} EntityA#entityBList: [EntityA{myIdA=1, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}, EntityB{myIdB=3, strB='testStringB'}]}, EntityA{myIdA=2, entityBList=[EntityB{myIdB=3, strB='testStringB'}, EntityB{myIdB=4, strB='testStringB2'}]}]
Example ProjectDependencies 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.
Implements javax.persistence:javax.persistence-api version 2.1 - JDK 1.8
- Maven 3.3.9
|
|