JAVA Tutorials

Hibernate Associations

Hibernate Associations technology handles how to persist java objects. But, it is possible only when the object has the XML-file that describes how to map it, or the object is annotated with hibernate annotations. In another case, the objects will be just simple plain java objects without relation to the database tables. Very often several entities can be related. In this situation, they must have references from each other. Such objects can have unidirectional or bidirectional references. We are going to understand in details how to deal with such situations.

Java objects can contain references to one or several other Java objects. They can have direct references as an embedded property or field. In the case of indirect references,  it is usually implemented via arrays, sets, lists, etc. These associations are represented in the database with foreign key relationships. 

If only one of the pair of Java classes contains a reference to the other, the association is called unidirectional. In the cases of the mutual association, we get the bidirectional relation.

The widespread beginner’s mistake in designing entity models is to try to make all associations bidirectional.  It is important to remember that associations that do not look like a natural part of the model of your object should not be forced into it.

Before starting with code we need to create User and Address tables and relationships in our MySql database exampledb by running queries:

create table exampledb.USER (
  user_id INT NOT NULL auto_increment,
  first_name VARCHAR(100) default NULL,
  last_name  VARCHAR(100) default NULL,
  PRIMARY KEY (user_id)
);
create table exampledb.address (
  address_id INT NOT NULL auto_increment,
  city VARCHAR(20) default NULL,
  address  VARCHAR(20) default NULL,
  PRIMARY KEY (address_id),
  CONSTRAINT user_address FOREIGN KEY (address_id) REFERENCES user(user_id) ON DELETE CASCADE
);

Here are our entities in code:

package edu.hibernate.example;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@Table(name = "User")
public class UserEntity implements Serializable {
@Id
@Column(name = "user_id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name", unique = false, nullable = false, length = 100)
private String firstName;
@Column(name = "last_name", unique = false, nullable = false, length = 100)
private String lastName;

@OneToOne(mappedBy="user", cascade = CascadeType.ALL)
AddressEntity address;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public AddressEntity getAddress() {
return address;
}

public void setAddress(AddressEntity address) {
this.address = address;
}

public Integer getId() {
return id;
}
}
package edu.hibernate.example;

import java.io.Serializable;

import javax.persistence.*;

@Entity
@Table(name = "Address")
public class AddressEntity  implements Serializable{
@Id
@Column(name = "address_id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
 
@Column(name = "city", unique = false, nullable = false, length = 20)
private String city;
   
@Column(name = "address", unique = false, nullable = false, length = 20)
private String address;
 
@OneToOne
@PrimaryKeyJoinColumn
UserEntity user;

//getters and setters
}
And, the second entity:
package edu.hibernate.example;

import java.io.Serializable;

import javax.persistence.*;

@Entity
@Table(name = "Address")
public class AddressEntity implements Serializable {
@Id
@Column(name = "address_id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@Column(name = "city", unique = false, nullable = false, length = 20)
private String city;

@Column(name = "address", unique = false, nullable = false, length = 20)
private String address;

@OneToOne
@PrimaryKeyJoinColumn
UserEntity user;

//getters and setters
}

In our case, with cascade operations and one-to-one relationships, it is enough to same just one entity into the database. Let’s create User and Address objects, save one of them into the database. After, we will create a new session and get our entities from the database to make sure that both User and Address objects were persisted.

package edu.hibernate.example;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

public class HibernateExample {

public static void main(String[] args) {
Configuration configuration = new Configuration();
configuration.addAnnotatedClass(edu.hibernate.example.UserEntity.class);
configuration.addAnnotatedClass(edu.hibernate.example.AddressEntity.class);
Session session1 = configuration.configure().buildSessionFactory().openSession();
 
session1.beginTransaction();

// Create new User object
UserEntity user = new UserEntity();
user.setFirstName("Jozeph");
user.setLastName("Jonson");

// Create new Address object
AddressEntity address = new AddressEntity();
address.setCity("Berlin");
address.setAddress("High str., 111");

user.setAddress(address);
address.setUser(user);
session1.save(user);
// session1.save(address);

session1.getTransaction().commit();
Integer userId = user.getId();
Integer addressId = address.getId();

Session session2 = configuration.configure().buildSessionFactory().openSession();
session2.beginTransaction();
UserEntity userDB = (UserEntity) session2.get(UserEntity.class, userId);
AddressEntity addressDB = (AddressEntity) session2.get(AddressEntity.class, addressId);

System.out.println(userDB.getId());
System.out.println(userDB.getAddress().getId());
System.out.println(addressDB.getId());
System.out.println(addressDB.getUser().getId());

}
}

There are two more ways to create one-to-one relationships that are less popular. For example, we can create one more table to store keys of User and Address tables, one record is responsible for one relationship between User and Address objects. The table is called a common join table.

One more way is to create a one-to-one mapping with a shared primary key

In this technique, we have to use a common primary key value in both the tables. 

One-to-many association

In a one-to-many approach, both entities are responsible for creating the relationship and maintaining it. The UserEntity needs to declare one-to-many relationships, the CarEntity declares is many-to-one from its end. Let’s look at the code of User and Car entities.

package edu.hibernate.example;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.*;

@Entity
@Table(name = "User")
public class UserEntity implements Serializable {
@Id
@Column(name = "user_id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name", unique = false, nullable = false, length = 100)
private String firstName;
@Column(name = "last_name", unique = false, nullable = false, length = 100)
private String lastName;

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "USERE_ID")
private Set<CarEntity> cars;

// Getters and setters
}
package edu.hibernate.example;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "Car")
public class CarEntity implements Serializable {
@Id
@Column(name = "car_id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@Column(name = "model", unique = false, nullable = false, length = 20)
private String model;

@ManyToOne
private UserEntity user;

// Getters and setters
}

Besides one-to-many mapping with a foreign key association, Hibernate also allows doing one-to-many mapping with a join table.

Many-to-many association

Hibernate many-to-many mapping is between two entities where one can have a relation with multiple another entity and vise versa. For example,  a user can be subscribed to several sites with the news. Every site with the news has a lot of users. Here is the schema:

Let’s look at the code of out entities:

package edu.hibernate.example;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.*;

@Entity
@Table(name = "User")
public class UserEntity implements Serializable {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name", unique = false, nullable = false, length = 100)
private String firstName;
@Column(name = "last_name", unique = false, nullable = false, length = 100)
private String lastName;

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name="USER_SUBSCRIPTIONS", joinColumns={@JoinColumn(referencedColumnName="ID")}, inverseJoinColumns={@JoinColumn(referencedColumnName="ID")})  
    private Set<SubscriptionEntity> subscriptions;
//Getters and setters 
}

package edu.hibernate.example;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.*;

@Entity
@Table(name = "Subscription")
public class SubscriptionEntity implements Serializable {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name", unique = false, nullable = false, length = 20)
private String name;
@Column(name = "link", unique = false, nullable = false, length = 100)
private String link;

@ManyToMany(mappedBy="subscriptions")
private Set<UserEntity> subscriptions;
 
//Getters and setters 

}

UserEntity class is the owner entity, that is responsible for making the association and maintaining it. For this entity, we have used @JoinTable annotation. SubcriptionEntity is our mapped entity, which is mapped to UserEntity using the “mappedBy” attribute. Also, we user annotation @ManyToMany in both entities. Here is the way to work on such kinds of relationships.

package edu.hibernate.example;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

public class HibernateExample {

public static void main(String[] args) 
    {
Configuration configuration = new Configuration();
configuration.addAnnotatedClass(edu.hibernate.example.UserEntity.class);
configuration.addAnnotatedClass(edu.hibernate.example.SubscriptionEntity.class);
Session session = configuration.configure().buildSessionFactory().openSession();

        SubscriptionEntity site1 = new SubscriptionEntity();
        SubscriptionEntity site2 = new SubscriptionEntity();
        Set<SubscriptionEntity> subscriptions = new HashSet<SubscriptionEntity>();
        subscriptions.add(site1);
        subscriptions.add(site2);
        
        UserEntity user1 = new UserEntity();
        UserEntity user2 = new UserEntity();     
        Set<UserEntity> users = new HashSet<UserEntity>();
        users.add(user1);
        users.add(user2);
        user1.setSubscriptions(subscriptions);
        user2.setSubscriptions(subscriptions);
 
        session.save(user1);
        session.save(user2);
         
        session.getTransaction().commit();
    }
}

We have created two instances of users and two instances of subscriptions. It is enough to save just user entities, all data about subscriptions and relationships will be persisted too.

Facebook Comments
Tags

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Check Also
Close
Back to top button
Close
Close