Working with JPA Entity Relationships

1. Implementing One-to-One Relationships

Example: Bidirectional one-to-one mapping

@Entity class User {
  @Id @GeneratedValue Long id;
  @OneToOne(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
  Profile profile;
}
@Entity class Profile {
  @Id @GeneratedValue Long id;
  @OneToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="user_id", unique=true)
  User user;
}

2. Implementing One-to-Many Relationships

Side Annotation
Owning (FK) @ManyToOne @JoinColumn(name="parent_id")
Inverse @OneToMany(mappedBy="parent")
Helper Add addChild()/removeChild() methods to maintain both sides

3. Implementing Many-to-One Relationships

Example: Many-to-one with lazy loading

@Entity class LineItem {
  @Id @GeneratedValue Long id;
  @ManyToOne(fetch=FetchType.LAZY, optional=false)
  @JoinColumn(name="order_id", nullable=false)
  Order order;
}
Warning: Always set fetch=LAZY on @ManyToOne to avoid hidden N+1 fetches.

4. Implementing Many-to-Many Relationships

Example: Many-to-many with join table

@Entity class Course {
  @ManyToMany
  @JoinTable(name="course_student",
    joinColumns=@JoinColumn(name="course_id"),
    inverseJoinColumns=@JoinColumn(name="student_id"))
  Set<Student> students = new HashSet<>();
}
Tip Reason
Use Set not List Avoid MultipleBagFetchException
Promote to entity if join carries data e.g. enrollment date

5. Using Bidirectional Relationships

Concept Detail
mappedBy On inverse side; references owning field
Owning side Holds FK; updates persist
Sync helper Manually keep both sides in sync
toString() Avoid including bidirectional collections (StackOverflow)

6. Using Cascade Operations

CascadeType Effect
PERSIST Save children when parent saved
MERGE Merge propagates
REMOVE Delete children with parent
REFRESH Reload children
DETACH Detach children
ALL All of the above

7. Configuring Fetch Types (LAZY vs EAGER)

FetchType When to Use
LAZY Default for collections; safe choice
EAGER Almost never — leads to N+1 + over-fetch
JOIN FETCH Per-query eager loading
EntityGraph Declarative fetch plan per call

8. Using @JoinColumn for Foreign Keys

Example: JoinColumn with named FK constraint

@ManyToOne
@JoinColumn(name="customer_id",
            referencedColumnName="id",
            nullable=false,
            foreignKey=@ForeignKey(name="fk_order_customer"))
Customer customer;

9. Using @JoinTable for Join Tables

Attribute Purpose
name Join table name
joinColumns FK to owning side
inverseJoinColumns FK to other side
uniqueConstraints Composite unique

10. Handling Orphan Removal

Example: Cascade delete with orphan removal

@OneToMany(mappedBy="order", cascade=CascadeType.ALL, orphanRemoval=true)
List<LineItem> items;
// order.getItems().remove(li); // triggers DELETE
Note: Different from CascadeType.REMOVE — orphanRemoval triggers when reference is removed from collection.

11. Using @EntityGraph for Fetch Optimization

Example: Entity graph to avoid N+1

@EntityGraph(attributePaths = {"customer", "items.product"})
@Query("select o from Order o where o.id = :id")
Optional<Order> findByIdWithDetails(@Param("id") Long id);

// Or named graph
@NamedEntityGraph(name="Order.detail",
  attributeNodes = {@NamedAttributeNode("items"), @NamedAttributeNode("customer")})