HomeHibernatemany-to-many bidirectional association

many-to-many bidirectional association

many-to-many bidirectional mapping :

In a relational database in a many-to-many relationship, a row in table X can have  more than one matching row in table Y, a row in table Y can have more than one matching row in table X.

In Object oriented programming, one instance of entity refers to multiple instances of another entity and an instance of that another entity refers to multiple instances of the other entity in the  relation called many-to-many relation.

In this tutorial used the relationship between Engineering Branch and Subjects that are having each Engineering branch in a semester. In an Engineering college each Branch have many Subjects and each Subject may appear in many Engineering branch semester.

many-to-many  Tables structure in Database :

many to many

what is join table?

A join table is a table in database that represents the multiple references of one or more table . In other words a join table is used to refer multiple records of one or more tables by using foreign key constraints. Below image illustrates more about many-to-many association.

Join Table in many to many associations in JPA and Hibernate

Technologies Used in following example :

  • JPA 2.1
  • Hibernate 5.2.6
  • MySql 8.0
  • Maven 3
  • Spring Tool Suite (STS) 3.9.8
  • Java 1.8

what is bidirectional?

  • Bidirectional relationship provides navigational access in both directions, so that you can access the other side entity without explicit queries.

Subject.java mapping :

/**
 * The persistent class for the Subject database table.
 * 
 */
@Entity
public class Subject implements Serializable {
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name="SUBJECT_ID")
    private int subjectId;
 
    @Column(name="SUBJECT_DESC")
    private String subjectDesc;
 
    @Column(name="SUBJECT_NAME")
    private String subjectName;
 
    //bi-directional many-to-many association to Branch
    @ManyToMany(mappedBy="subjects",cascade = CascadeType.ALL)
    private Set<Branch> branches = new HashSet<Branch>();
 
   //Setters and getters
}

Branch.java mapping :

/**
 * The persistent class for the BRANCH database table.
 * 
 */
@Entity
public class Branch implements Serializable {
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name="BRANCH_ID")
    private int branchId;
 
    @Column(name="BRANCH_NAME")
    private String branchName;
 
    @Column(name="BRANCH_SHORT_NAME")
    private String branchShortName;
 
    private String description;
 
    //bi-directional many-to-many association to Subject
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="BRANCH_SUBJECT"
        , joinColumns={
            @JoinColumn(name="BRANCH_ID")
            }
        , inverseJoinColumns={
            @JoinColumn(name="SUBJECT_ID")
            }
        )
    private Set<Subject> subjects;

   //Setters and getters
}

@JoinTable

  • @JoinTable Used in the mapping of associations. It is specified on the owning side of an association.
  • @JoinTable can be used with embeddable types as well.When a join table is used in mapping a relationship with an embeddable class on the owning side of the relationship, the containing entity rather than the embeddable class is considered the owner of the relationship.

To Understand more about @JoinTable mapping in entity associations see :
Key points to understand associations

many-to-many  bidirectional mapping testing :

/**
 * JPA Many-To-Many BiDirectional
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        EntityManagerFactory emf = null;
        EntityManager entityManager = null;
        EntityTransaction transaction = null;
        
        try{
            emf = Persistence.createEntityManagerFactory("jbd-pu");
            entityManager = emf.createEntityManager();
            transaction = entityManager.getTransaction();
            transaction.begin();
            
            Branch branch1 = getBranch1();//CSE Branch in Engineering
            Branch branch2 = getBranch2();//IT Branch in Engineering
            Subject subject1 = getSubject1();
            Subject subject2 = getSubject2();
            Subject subject3 = getSubject3();
            branch1.setSubjects(new HashSet<Subject>());
            branch1.addSubject(subject1);//Software Engineering
            branch1.addSubject(subject2);//Distributed System
            branch2.setSubjects(new HashSet<Subject>());
            branch2.addSubject(subject1);//Software Engineering
            branch2.addSubject(subject3);//Business Analysis and Optimization
            
            subject1.addBranch(branch1);
            subject1.addBranch(branch2);
            subject2.addBranch(branch1);
            subject3.addBranch(branch2);
            
            entityManager.persist(branch1);
            entityManager.persist(branch2);
            
            transaction.commit();
            Subject retrievedSubject = entityManager.find(Subject.class, new ArrayList<Subject>(branch1.getSubjects()).get(0).getSubjectId());
            for(Branch retrivedBranch : retrievedSubject.getBranches()){
                 System.err.println("Branch "+new ArrayList<Branch>(retrievedSubject.getBranches()).indexOf(retrivedBranch)+" : ");
                 System.err.println(retrivedBranch.getBranchName());
            }
            
        }catch(Exception e){
            transaction.rollback();
            e.printStackTrace();
        }finally{
            entityManager.close();
            emf.close();
        }
    }
    
    private static Subject getSubject1(){
        Subject subject = new Subject();
        subject.setSubjectName("Software Engineering");
        subject.setSubjectDesc("Apply key aspects of software engineering processes for the development of a complex software system");
        
        return subject;
    }
    
    private static Subject getSubject2(){
        Subject subject = new Subject();
        subject.setSubjectName("Distributed System");
        subject.setSubjectDesc("Explore recent advances in distributed computing systems");
        
        return subject;
    }
    
    private static Subject getSubject3(){
        Subject subject = new Subject();
        subject.setSubjectName("Business Analysis and Optimization");
        subject.setSubjectDesc("understand the Internal and external factors that impact the business strategy");
        
        return subject;
    }
    
    private static Branch getBranch1(){
        Branch branch = new Branch();
        branch.setBranchName("Computer Science and Engineering");
        branch.setBranchShortName("CSE");
        branch.setDescription("CSE department offers courses under ambitious curricula in computer science and computer engineering..");
        
        return branch;
    }
    
    private static Branch getBranch2(){
        Branch branch = new Branch();
        branch.setBranchName("Information Technology");
        branch.setBranchShortName("IT");
        branch.setDescription("IT is the business side of computers - usually dealing with databases, business, and accounting");
        
        return branch;
    }
}

Console output :

INFO - HHH000400: Using dialect: org.hibernate.dialect.MySQLInnoDBDialect
INFO - HHH000397: Using ASTQueryTranslatorFactory
Hibernate: insert into Branch (BRANCH_NAME, BRANCH_SHORT_NAME, description) values (?, ?, ?)
Hibernate: insert into Subject (SUBJECT_DESC, SUBJECT_NAME) values (?, ?)
Hibernate: insert into Branch (BRANCH_NAME, BRANCH_SHORT_NAME, description) values (?, ?, ?)
Hibernate: insert into Subject (SUBJECT_DESC, SUBJECT_NAME) values (?, ?)
Hibernate: insert into Subject (SUBJECT_DESC, SUBJECT_NAME) values (?, ?)
Hibernate: insert into BRANCH_SUBJECT (BRANCH_ID, SUBJECT_ID) values (?, ?)
Hibernate: insert into BRANCH_SUBJECT (BRANCH_ID, SUBJECT_ID) values (?, ?)
Hibernate: insert into BRANCH_SUBJECT (BRANCH_ID, SUBJECT_ID) values (?, ?)
Hibernate: insert into BRANCH_SUBJECT (BRANCH_ID, SUBJECT_ID) values (?, ?)
Branch 0 : 
Computer Science and Engineering
Branch 1 : 
Information Technology

Download Application – JPA-ManyToMany-BiDirection.zip (16 KB)

LEAVE A REPLY

Please enter your comment!
Please enter your name here