Hibernate Tutorial
Core Hibernate
Hibernate Mapping
Hibernate Annotations
Hibernate with Spring Framework
Hibernate with Database
Hibernate Log4j
Inheritance Mapping
Bidirectional associations in Hibernate allow you to navigate and manipulate objects on both sides of the relationship. This tutorial will cover how to create a bidirectional association between two entities using Hibernate.
Let's demonstrate a bidirectional association using a classic One-to-Many
relationship between Author
and Book
. An author can write multiple books, but each book is written by one author.
@Entity @Table(name="author") public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @OneToMany(mappedBy="author", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Book> books = new ArrayList<>(); // Constructors, getters, setters, etc. }
@Entity @Table(name="book") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String title; @ManyToOne @JoinColumn(name="author_id") private Author author; // Constructors, getters, setters, etc. }
Key Points:
In Author
, the @OneToMany
annotation defines the one-to-many relationship. The mappedBy
attribute points to the property in the Book
entity that owns the relationship. This ensures that only the Book
side manages the foreign key in the database.
In Book
, the @ManyToOne
annotation denotes the many-to-one side of the relationship. The @JoinColumn
annotation indicates the foreign key column in the book
table.
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Author author = new Author(); author.setName("George Orwell"); Book book1 = new Book(); book1.setTitle("1984"); book1.setAuthor(author); Book book2 = new Book(); book2.setTitle("Animal Farm"); book2.setAuthor(author); author.getBooks().add(book1); author.getBooks().add(book2); session.persist(author); // This will also save the associated books. tx.commit(); session.close();
Session session = sessionFactory.openSession(); Author retrievedAuthor = session.get(Author.class, 1); List<Book> booksByAuthor = retrievedAuthor.getBooks(); Book retrievedBook = session.get(Book.class, 1); Author authorOfBook = retrievedBook.getAuthor(); session.close();
Manage Both Sides: When working with bidirectional associations, always remember to update both sides of the relationship to keep them in sync.
Use CascadeType.ALL
Wisely: In our example, we used CascadeType.ALL
which means operations like delete will be cascaded. If you delete an Author
, all his books will be deleted as well.
Lazy vs. Eager Fetching: Use FetchType.LAZY
(default for one-to-many) to load the associated entities on demand. Eager fetching (FetchType.EAGER
) can lead to performance issues if not used carefully.
Avoid Bi-directional ManyToMany
: Bi-directional many-to-many relationships can be confusing and should be used sparingly. If necessary, introduce a join entity in between to make the association clearer.
Equality and HashCode: Ensure that you properly implement equals()
and hashCode()
methods for your entities. The presence of bi-directional associations can complicate this, so always ensure both sides of the relationship are correctly accounted for.
Bidirectional associations provide a powerful way to map and navigate relationships in Hibernate. However, always be cautious of potential pitfalls, especially regarding database performance and object synchronization.
Hibernate bidirectional association example:
Bidirectional associations in Hibernate involve establishing relationships between entities in both directions.
@Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") private Long id; @OneToMany(mappedBy = "employee") private List<Project> projects; // Other properties and methods } @Entity @Table(name = "projects") public class Project { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "project_id") private Long id; @ManyToOne @JoinColumn(name = "employee_id") private Employee employee; // Other properties and methods }
Bidirectional one-to-one mapping in Hibernate:
One-to-one bidirectional mapping is achieved by defining @OneToOne
annotations on both sides of the association.
@Entity @Table(name = "person") public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "person_id") private Long id; @OneToOne(mappedBy = "person") private Address address; // Other properties and methods } @Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "address_id") private Long id; @OneToOne @JoinColumn(name = "person_id") private Person person; // Other properties and methods }
Mapping bidirectional many-to-one association in Hibernate:
Bidirectional many-to-one mapping is achieved by using @ManyToOne
and @OneToMany
annotations.
@Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") private Long id; @OneToMany(mappedBy = "employee") private List<Project> projects; // Other properties and methods } @Entity @Table(name = "projects") public class Project { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "project_id") private Long id; @ManyToOne @JoinColumn(name = "employee_id") private Employee employee; // Other properties and methods }
Bidirectional one-to-many relationship in Hibernate:
One-to-many bidirectional mapping is established using @OneToMany
and @ManyToOne
annotations.
@Entity @Table(name = "departments") public class Department { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "department_id") private Long id; @OneToMany(mappedBy = "department") private List<Employee> employees; // Other properties and methods } @Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") private Long id; @ManyToOne @JoinColumn(name = "department_id") private Department department; // Other properties and methods }
Managing bidirectional associations in Hibernate:
When managing bidirectional associations, ensure that both sides of the association are properly synchronized.
Employee employee = new Employee(); Project project = new Project(); // Bidirectional association employee.getProjects().add(project); project.setEmployee(employee); session.save(employee); session.save(project);
Cascade options in bidirectional associations in Hibernate:
Cascade options define how operations (such as save, update, delete) should cascade from one entity to its associated entities.
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL) private List<Project> projects;
Fetching strategies in bidirectional associations:
Choose appropriate fetching strategies (EAGER
or LAZY
) for bidirectional associations to control when associated entities are loaded.
@OneToMany(mappedBy = "employee", fetch = FetchType.LAZY) private List<Project> projects;