@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)
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")})