# @ManyToOne, @OneToMany and the Owning Side — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/r-basic

> Map one-to-many relationships with the correct owning side and helper methods.

## Foreign keys as object references

Most relationships are **many-to-one** at the database level: an `order_lines.order_id` foreign key. Map it with **`@ManyToOne`** (plus `@JoinColumn(name = "order_id")`) on the many side, which is the **owning side**: the side whose field determines the foreign key value. If you also want navigation from the parent, add **`@OneToMany(mappedBy = "order")`** on the one side; `mappedBy` marks it as the **inverse side**, which Hibernate ignores when writing the foreign key. A very common bug is updating only the inverse side (`order.getLines().add(line)`) without setting `line.setOrder(order)`, so the foreign key is never written. Keep both sides in sync with **helper methods** (`addLine`, `removeLine`) on the parent. A unidirectional `@OneToMany` without `mappedBy` creates an extra join table or extra UPDATE statements, so prefer bidirectional mappings or just the `@ManyToOne`. Consider whether you need the collection at all: loading an order's lines through a query is often simpler than mapping a large collection.

## Owning side and inverse side

The many side owns the foreign key; the one side mirrors it with mappedBy.

![Two boxes: one on the left with a list icon, one on the right with a key icon; a solid arrow from right to left and a dashed arrow back.](assets/figures/hibernate-jpa/section-4-map.svg) — Figure 4.1 — @ManyToOne owning the foreign key, @OneToMany(mappedBy) as the inverse side.

## A bidirectional one-to-many with helper methods

The helper keeps both sides consistent so the foreign key is always written.

```java
@Entity
@Table(name = "orders")
public class PurchaseOrder {
    @Id @GeneratedValue private Long id;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderLine> lines = new ArrayList<>();

    public void addLine(String sku, int qty, BigDecimal unitPrice) {
        OrderLine line = new OrderLine(this, sku, qty, unitPrice);
        lines.add(line);                         // inverse side
    }

    public void removeLine(OrderLine line) {
        lines.remove(line);
        line.detachFromOrder();                  // keep both sides in sync
    }
}

@Entity
public class OrderLine {
    @Id @GeneratedValue private Long id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)   // owning side: writes order_id
    @JoinColumn(name = "order_id")
    private PurchaseOrder order;

    private String sku;
    private int quantity;
    private BigDecimal unitPrice;

    protected OrderLine() { }
    OrderLine(PurchaseOrder order, String sku, int quantity, BigDecimal unitPrice) {
        this.order = order; this.sku = sku; this.quantity = quantity; this.unitPrice = unitPrice;
    }
    void detachFromOrder() { this.order = null; }
}
```

## mappedBy names the field, not the column

`@OneToMany(mappedBy = "order")` refers to the Java field `order` in `OrderLine`, not the database column `order_id`. Getting this wrong produces a mapping exception at start-up.

**Quiz:** In a bidirectional one-to-many mapping, which side writes the foreign key?

- [ ] The @OneToMany side with mappedBy
- [ ] Both sides equally
- [x] The @ManyToOne side (the owning side)
- [ ] Neither; the database decides

*Answer:* The @ManyToOne side (the owning side). The owning side, the @ManyToOne field, determines the foreign key value.
