Relationship Basics
Tables Use Foreign Keys, Objects Use References
In the database, an order item points to its order with a foreign key column (order_items.order_id). In Java, an OrderItem object simply holds a reference to an Order object. A relationship mapping tells Hibernate how to turn one into the other.
| Annotation | Meaning | ShopEase example |
|---|---|---|
@ManyToOne | many rows of this entity point to one row of the other | many Products belong to one Category |
@OneToMany | one row has a collection of rows of the other | one Order has many OrderItems |
@OneToOne | exactly one row on each side | one Order has one Payment |
@ManyToMany | many on both sides, through a join table | a User wishlists many Products, a product is in many wishlists |
Unidirectional vs Bidirectional
- Unidirectional: only one class knows about the other.
Producthas acategoryfield, butCategoryhas no list of products. - Bidirectional: both classes have a field.
Order.itemsandOrderItem.order. You can navigate both ways, but you must keep both sides in sync. - The database is the same in both cases: one foreign key column. Bidirectional is a Java convenience, not a different table design.
Java objects Database tables ------------ --------------- Order ── items ──► [OrderItem,...] orders(id, user_id, status, total) ▲ │ ▲ └──────── order ─────────┘ order_items(id, order_id FK, product_id FK, quantity, price)
The Owning Side and mappedBy
In a bidirectional relationship there is still only one foreign key. JPA needs to know which Java field controls it. That field is the owning side. The other side says mappedBy = "fieldName" and is the inverse side: Hibernate ignores it when writing the foreign key.
- For
@ManyToOne/@OneToMany, the many side (OrderItem.order) is always the owning side. - For
@OneToOneand@ManyToMany, you choose: the side withoutmappedByowns it. - Only changes on the owning side are saved. Adding an item to
order.getItems()without settingitem.setOrder(order)storesorder_id = NULL.
Note: mappedBy holds the Java field name on the other class (e.g. "order"), not a column name.
Practice
Exercise: In ShopEase, a CartItem belongs to one User and one Product. Which annotation goes on CartItem.user, and which side owns the relationship?
Show answer
// CartItem is the "many" side: many cart items per user.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user; // owning side: holds the cart_items.user_id foreign key
// Optional inverse side on User:
@OneToMany(mappedBy = "user")
private List<CartItem> cartItems = new ArrayList<>();