офлайн
офлайн
ГлавнаяСвязи сущностей в JPA.md
---
tags: [databases, jpa, hibernate]
created: 2026-11-06
updated: 
---

Связи сущностей в JPA

Содержание

Шпаргалка по JPA: Аннотации и параметры связей

1. @JoinColumn

Зачем нужна:
Задает колонку внешнего ключа (FK) на owning side (владеющей стороне) связи, когда связь хранится не через отдельную таблицу, а через обычную колонку в текущей таблице.

Типичные сценарии:

  • @ManyToOne (всегда на этой стороне)
  • Owning side у @OneToOne
  • Иногда однонаправленная (unidirectional) связь @OneToMany

Пример:

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

Основные параметры:

  • name — имя FK-колонки в текущей таблице.
  • referencedColumnName — на какую колонку целевой таблицы ссылаемся (по умолчанию PK).
  • nullable — может ли FK быть пустым (NULL).
  • unique — уникальна ли колонка.
  • insertable / updatable — участвует ли колонка в соответствующих SQL-запросах.
  • foreignKey — настройка constraint (ограничения) внешнего ключа.

2. mappedBy

Зачем нужна:
Используется на inverse side (обратной стороне) двунаправленной связи. Она сообщает Hibernate: «Я не управляю связью. Настоящий мэппинг уже описан в поле X другой сущности».

mappedBy не создает колонку или таблицу.

Типичные сценарии:

  • @OneToMany(mappedBy = "...")
  • @OneToOne(mappedBy = "...")
  • @ManyToMany(mappedBy = "...")

Пример:

// В классе User
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();

Важно: Значение mappedBy — это имя Java-поля в связанной сущности, а не имя колонки в БД.

Если в Order поле называется private User user;, то в User пишем mappedBy = "user".


3. @JoinTable

Зачем нужна:
Описывает связь через промежуточную таблицу (join table).

Типичные сценарии:

  • @ManyToMany (стандартный способ)
  • Unidirectional @OneToMany (иногда, чтобы избежать лишней колонки в дочерней таблице)

Пример:

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

Как понимать параметры:

  • name — имя промежуточной таблицы.
  • joinColumns — FK на текущую сущность (владельца).
  • inverseJoinColumns — FK на связанную сущность (другую сторону).

4. cascade (Каскадирование)

Зачем нужна:
Определяет, как операции над родительской сущностью (Parent) распространяются на связанные сущности (Children).

Типы каскадирования (CascadeType):

  • PERSIST — сохранение родителя сохранит и детей.
  • MERGE — обновление родителя обновит и детей.
  • REMOVE — удаление родителя удалит детей.
  • DETACH / REFRESH — отвязка или обновление состояния.
  • ALL — все операции сразу.

Пример:

@OneToMany(mappedBy = "order", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<OrderLine> lines = new ArrayList<>();

Когда использовать: Когда «ребенок» жизненно зависит от родителя (например, Order -> OrderLine). Если это независимые сущности (например, Article -> Tag), каскадное удаление обычно не нужно.


5. orphanRemoval (Удаление сирот)

Зачем нужна:
Специфичный для Hibernate/JPA параметр. Удаляет дочернюю сущность из БД, если ссылка на неё была удалена из коллекции родителя.

Пример:

@OneToMany(mappedBy = "user", orphanRemoval = true)
private List<Order> orders;

Поведение:

user.getOrders().remove(order1); // При сохранении order1 будет физически удален из базы

Отличие от cascade = REMOVE:

  • cascade = REMOVE: Если удаляем User, удаляются все его Orders.
  • orphanRemoval = true: Если мы просто убираем Order из списка внутри User, этот Order удаляется из базы.

Быстрая сводка (Cheat Sheet)

ПараметрГде писать?Суть
@JoinColumnOwning sideНастраивает колонку FK в таблице.
mappedByInverse sideУказывает на поле-владельца связи.
@JoinTableОбычно @ManyToManyСоздает третью таблицу для связи.
cascadeParent sideПрокидывает save/update/delete на детей.
orphanRemovalParent sideЧистит базу от сущностей, которые «выпали» из коллекции.
main48 заметок487 слов3 мин чтения