Логотип Workflow

Article

Updated at:

Relationships

Stage 5 - Relationships: One-to-One, One-to-Many, and Many-to-Many

Applications rarely store isolated records. A user has a profile, a user places many orders, a category contains many products, and students can attend many courses. In the database a relationship is a key structure; in Java it becomes an object reference or collection. In a relational database, these connections are represented with primary keys, foreign keys, and sometimes join tables. In JPA, they are represented with entity references and relationship annotations.

Entity relationships

One-to-One

One-to-one means one row in table A is connected to one row in table B. A common example is User and Profile: one user has one profile, and one profile belongs to one user. In the database, one table usually contains a foreign key with a unique constraint.

@OneToOne
@JoinColumn(name = "profile_id")
private Profile profile;

@OneToOne describes the relationship type. @JoinColumn describes the foreign key column used to join the tables. One-to-one should not be overused. If two groups of fields always load and change together, they may belong in the same table. A separate entity is useful when the lifecycle or security rules are different.

One-to-Many and Many-to-One

One-to-many means one parent is connected to many children. A user can have many orders. In the database, the foreign key usually sits on the many side: the orders table has user_id. In JPA, the child side is usually modeled with @ManyToOne, and the parent collection can be modeled with @OneToMany(mappedBy = "user").

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@OneToMany(mappedBy = "user")
private List<Order> orders = new ArrayList<>();

mappedBy means the other side owns the relationship. The owning side is the side with the foreign key column. A frequent mistake is to put @JoinColumn on both sides or to forget to set both object references in code. If you add an order to user.getOrders(), you should also set order.setUser(user) so the object graph and the database foreign key agree.

Many-to-Many and join tables

Many-to-many means many rows on one side can connect to many rows on the other side. Students and courses are a classic example. A student can attend many courses, and a course can have many students. A relational database cannot store this directly in one column, so it uses a join table such as student_courses with student_id and course_id.

@ManyToMany
@JoinTable(
    name = "student_courses",
    joinColumns = @JoinColumn(name = "student_id"),
    inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();

Many-to-many is convenient for simple links, but in business systems the join often has extra data: enrollment date, status, progress, or grade. When the relationship has its own fields, model the join table as a separate entity such as Enrollment.

Modeling questionCorrect relational answerJPA mapping consequence
Can one profile belong to two users?No, so the foreign key must be unique.Use @OneToOne; keep the owning side where the foreign key lives.
Where is the user-order foreign key stored?On orders.user_id, because many orders can point to one user.Order owns the relation with @ManyToOne and @JoinColumn.
Why does User.orders need mappedBy?The users table does not store a list of order ids.@OneToMany(mappedBy = "user") says the collection is mirrored from Order.user.
Why does student-course need a separate table?Both sides can have many rows, so one foreign key column is not enough.Use @JoinTable, or model the join as Enrollment when it has its own fields.
When should cascade delete be avoided?When the child row is shared or has an independent lifecycle.Avoid CascadeType.REMOVE on shared relations such as many-to-many.

Cascades and orphan removal

Cascade controls whether an operation on one entity is propagated to related entities. PERSIST saves new related entities. MERGE merges related detached entities. REMOVE deletes related entities. ALL includes all cascade operations. Cascades are powerful and dangerous: CascadeType.REMOVE on a many-to-many relationship can delete shared records accidentally.

orphanRemoval = true means a child removed from a parent collection should be deleted from the database. It is useful for true ownership, such as order items inside one order. It is not appropriate when the child can exist independently.

Practice

Model User and Profile as one-to-one, User and Order as one-to-many/many-to-one, and Student and Course as many-to-many. Then refactor student-course into an Enrollment entity and add enrolledAt. This shows why many-to-many is often only a first step.

Understanding checklist

  • I can identify where the foreign key belongs.
  • I understand mappedBy and owning side.
  • I know why many-to-many uses a join table.
  • I can choose cascades carefully.
  • I understand when orphanRemoval is appropriate.

Please login to pass quizzes.

Practice

Interactive practice

Complete tasks and check your answer instantly.