Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
FAQs Support
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

Hibernate Relationships

Relationship Types

AnnotationExampleDB Representation
@OneToOneUser ↔ UserProfileForeign key in one table
@OneToManyUser → OrdersForeign key in child table
@ManyToOneOrder → UserForeign key in this table
@ManyToManyStudent ↔ CourseJoin table
@OneToOne and @OneToMany / @ManyToOne
// @OneToOne: User has one UserProfile
@Entity
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;

    // Owning side: has the foreign key column
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "profile_id", unique = true)
    private UserProfile profile;
}

@Entity
public class UserProfile {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String bio;
    private String website;

    // Inverse side (mappedBy = field name in User)
    @OneToOne(mappedBy = "profile")
    private User user;
}
// @OneToMany / @ManyToOne: User has many Orders
@Entity
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;

    // One user has many orders
    // mappedBy = field name in Order that owns the relationship
    @OneToMany(mappedBy = "user",
               cascade = CascadeType.ALL,
               fetch = FetchType.LAZY,
               orphanRemoval = true)
    private List<Order> orders = new ArrayList<>();

    // Helper method to maintain bidirectional consistency
    public void addOrder(Order order) {
        orders.add(order);
        order.setUser(this);
    }
}

@Entity
@Table(name = "orders")
public class Order {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private java.math.BigDecimal total;

    // Many orders belong to one user
    // This side owns the relationship (has the FK column)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;
}

Cascade Types and Fetch Types

Cascade TypeDescription
ALLAll operations cascade (PERSIST, MERGE, REMOVE, REFRESH, DETACH)
PERSISTSave cascades to related entities
MERGEMerge cascades to related entities
REMOVEDelete cascades to related entities
REFRESHRefresh cascades to related entities
DETACHDetach cascades to related entities
@ManyToMany with Join Table
// @ManyToMany: Student can enroll in many Courses
// Course can have many Students
@Entity
public class Student {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // Owning side: defines the join table
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE},
                fetch = FetchType.LAZY)
    @JoinTable(
        name = "student_course",           // Join table name
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    private Set<Course> courses = new HashSet<>();
}

@Entity
public class Course {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;

    // Inverse side
    @ManyToMany(mappedBy = "courses")
    private Set<Student> students = new HashSet<>();
}

// Usage
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

Student student = new Student("Alice");
Course java = new Course("Java Programming");
Course spring = new Course("Spring Framework");

student.getCourses().add(java);
student.getCourses().add(spring);
java.getStudents().add(student);
spring.getStudents().add(student);

session.persist(student);
session.persist(java);
session.persist(spring);

tx.commit();
session.close();
Fetch Types - EAGER vs LAZY
// EAGER: related entities loaded immediately with parent
// Default for @ManyToOne and @OneToOne
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "department_id")
private Department department; // Loaded with Employee in same query

// LAZY: related entities loaded only when accessed
// Default for @OneToMany and @ManyToMany
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Order> orders; // Loaded only when orders is accessed

// LAZY loading requires open session when accessing the collection
// Use JOIN FETCH in HQL to avoid N+1 problem:
List<User> users = session.createQuery(
    "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.orders", User.class)
    .list();
// This loads users AND their orders in a single query

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.