- In many-to-many association, a JPA entity has a collection reference of another entity.
- The entity having the collection reference is called 'source' entity', whereas the entity which is being referenced is called 'target entity'.
- To map many-to-many association to database tables, @ManyToMany annotation is used on the collection. We don't use any annotation on the target side unless it's a bidirectional relationship.
- An intermediate 'join' table is mapped along with the two tables (each for the source and the target entities).
- The join table has two foreign key columns. One foreign key column refers to the source table. The other foreign key column refers to the target table.
- In the join table, there is no unique key constraint on any of the two foreign key columns so that many-to-many multiplicity can be achieved.
- Having no unique foreign key in the join table also means that our collection can have duplicates and also same target entity can be shared among different instances of the source entity's collection.
- To use a customized join table or to map an existing join table with different attributes (names/columns), we can use @JoinTable annotation.
Example
@Entity
public class EntityA {
@Id
@GeneratedValue
private int myIdA;
@ManyToMany
private List<EntityB> entityBList;
.............
}
@Entity
public class EntityB {
@Id
@GeneratedValue
private int myIdB;
private String str;
.............
}
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] --------------------------- '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 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.setStr("testStringB");
EntityB entityB2 = new EntityB();
entityB2.setStr("testStringB 2");
EntityA entityA = new EntityA();
entityA.setEntityBList(Arrays.asList(entityB, entityB2, entityB));
EntityA entityA2 = new EntityA();
entityA2.setEntityBList(Arrays.asList(entityB, entityB2));
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(System.out::println);
em.close();
}
} Output-- Persisting entities -- --- native queries --------------------------- 'Select * from EntityA' 1 2 --------------------------- 'Select * from EntityB' [3, testStringB] [4, testStringB 2] --------------------------- 'Select * from ENTITYA_ENTITYB' [1, 3] [1, 4] [1, 3] [2, 3] [2, 4] -- Loading EntityA -- EntityA{myIdA=1, entityBList=[EntityB{myIdB=3, str='testStringB'}, EntityB{myIdB=4, str='testStringB 2'}, EntityB{myIdB=3, str='testStringB'}]} EntityA{myIdA=2, entityBList=[EntityB{myIdB=3, str='testStringB'}, EntityB{myIdB=4, str='testStringB 2'}]} -- Loading EntityB -- EntityB{myIdB=3, str='testStringB'} EntityB{myIdB=4, str='testStringB 2'}
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
|
|