Home Hibernate one-to-one bidirectional association

one-to-one bidirectional association

In a relational database in a one-to-one relationship, a row in table X can have no more than one matching row in table Y, and vice versa. X one-to-one relationship is created if both of the related columns are primary keys or have unique constraints.

In Object oriented programming, one instance of entity exactly refers to one instance of another entity in the  relation called one-to-one relation.

what is bidirectional?

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

Tables structure in Database :

one-to-one hibernate jpa

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

User.java Mapping

@Entity(name="USER")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name = "ID")
    private Long id;
    
    @Temporal(value=TemporalType.TIMESTAMP)
    @Column(name="CREATED_TIME")
    private Date creationTime;
    
    @Temporal(value=TemporalType.TIMESTAMP)
    @Column(name="UPDATED_TIME")
    private Date updatedTime;
    
    @Temporal(value=TemporalType.DATE)
    @Column(name="DOB")
    private Date dateofBirth;
    
    @Enumerated(value=EnumType.STRING)
    @Column(name="USER_TYPE")
    private UserType userType;
    
    @Column(name = "FIRST_NAME")
    private String firstName;
    
    @Column(name = "LAST_NAME")
    private String lastName;
    
    @OneToOne(mappedBy="user")  //defines a bidirectional relationship.
    private Credentials credentials;
 
 /* Getters and Setters */

mappedBy :

The mappedBy element defines a bidirectional relationship. This attribute allows you to refer the associated entities from both sides.

Credentials.java Mapping

@Entity(name="USER_CREDENTIALS")
public class Credentials {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name = "CREDS_ID")
    private Long credentialId;
    
    @Column(name = "USERNAME")
    private String userName;
    
    @Column(name = "PASSWORD")
    private String password;
    
    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="USER_ID")
    private User user;
 
 /* Getters and Setters */

Cascade :

  • Whenever rows in the parent table manipulated (inserted, updated, deleted) the respective rows of the child table with a matching key column will be manipulated as well. This is called Cascade in Database.
  • JPA translates entity state transitions to database DML statements.

@JoinColumn :

  • @JoinColumn Specifies a column for joining an entity association or element collection. The annotation @OneToOne indicates that this entity is the owner of the relationship. That is the corresponding table has a column with a foreign key to the referenced table.

To Understand mappedBy, Cascade and @JoinColumn mapping in entity associations see :
Key points to understand associations

Saving entities  :

/**
 * JPA One-To-One 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();
            
            User user = new User();
            user.setFirstName("Peter");
            user.setLastName("Milanovich");
            user.setCreationTime(new Date());
            user.setDateofBirth(new Date());
            user.setUserType(UserType.EMPLOYEE);
            
            Credentials credentials = new Credentials();
            credentials.setUserName("peterm");
            credentials.setPassword("password");
            
            user.setCredentials(credentials);
            credentials.setUser(user);
    
            //Credentials object having all the information (User and Credentials)
            entityManager.persist(credentials);
            transaction.commit();
            
        }catch(Exception e){
            transaction.rollback();
            e.printStackTrace();
        }finally{
            entityManager.close();
            emf.close();
        }
    }
}

Output :

INFO - HHH000400: Using dialect: org.hibernate.dialect.MySQLInnoDBDialect
INFO - HHH000397: Using ASTQueryTranslatorFactory
Hibernate: insert into USER (CREATED_TIME, DOB, FIRST_NAME, LAST_NAME, UPDATED_TIME, USER_TYPE) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into USER_CREDENTIALS (PASSWORD, USER_ID, USERNAME) values (?, ?, ?)
INFO - HHH000030: Cleaning up connection pool [jdbc:mysql://localhost:3306/jpa_JBD]

Testing bidirectional  navigation:

public class BiDirectionalTest {
 
    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();
            
            Credentials credential = entityManager.find(Credentials.class, new Long(2));
            
            System.err.println("================= From Credentials ===================");
            System.err.println("User Name: "+credential.getUserName());
            System.err.println("Password: "+credential.getPassword());
            //In Bi-direction we can navigate to other side entity(User)
            System.err.println("First Name : "+credential.getUser().getFirstName());
            System.err.println("Last Name : "+credential.getUser().getLastName());
            
            User user = entityManager.find(User.class, new Long(2));
            
            System.err.println("================= From User ===================");
            System.err.println("First Name : "+user.getFirstName());
            System.err.println("Last Name : "+user.getLastName());
            //In Bi-direction we can navigate to other side entity(Credentials)
            System.err.println("User Name: "+user.getCredentials().getUserName());
            System.err.println("Password: "+user.getCredentials().getPassword());
            
            
        }catch(Exception e){
            transaction.rollback();
            e.printStackTrace();
        }finally{
            entityManager.close();
            emf.close();
        }
    }
}

Output :

INFO - HHH000030: Cleaning up connection pool [jdbc:mysql://localhost:3306/jpa_JBD]
================= From Credentials ===================
User Name: peterm
Password: password
First Name : Peter
Last Name : Milanovich
================= From User ===================
First Name : Peter
Last Name : Milanovich
User Name: peterm
Password: password

Download Application – JPA-OneToOne-BiDirection.zip (15 KB)

Satish Varma
Satish Varmahttps://javabydeveloper.com
Satish is post graduated in master of computer applications and experienced software engineer with focus on Spring, JPA, REST, TDD and web development. Follow him on LinkedIn or Twitter or Facebook

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Stay in Touch

Categories