Понимание mappedBy аннотации в Hibernate

Я пытаюсь понять атрибут mappedBy аннотации @OneToMany в JPA. Я создал ниже пример, где у Клиента есть список Заказов:

@Entity
public class Customer {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   @OneToMany(mappedBy="customer")
   @OrderColumn(name="orders_index")
   public List<Order> getOrders() { return orders; }
   public void setOrders(List<Order> orders) { this.orders = orders; }
   private List<Order> orders;
}

@Entity
@Table(name="TBL_ORDER")
public class Order {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   public int getOrderNumber() { return orderNumber; }
   public void setOrderNumber(int orderNumber) { this.orderNumber = orderNumber; }
   private int orderNumber;

   @ManyToOne
   public Customer getCustomer() { return customer; }
   public void setCustomer(Customer customer) { this.customer = customer; }
   private Customer customer;
}

Теперь, когда я использую Hibernate для генерации таблиц, я вижу, что Hibernate создал только 2 таблицы:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), orders_index number(10,0), primary key (id))
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

Также, если я попытаюсь сохранить клиента и некоторые Заказы, я вижу ниже инструкции DML, сгенерированные Hibernate:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: update TBL_ORDER set orders_index=? where id=?

Почему hibernate попытался вставить и обновить запись в TBL_ORDER вместо простого запроса на вставку?

Теперь, если я удалю атрибут mappedBy и попытаюсь сгенерировать таблицы, на этот раз я вижу 3 таблицы:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table Customer_TBL_ORDER (Customer_id number(10,0) not null, orders_id number(10,0) not null, orders_index number(10,0) not null, primary key (Customer_id, orders_index))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), primary key (id))
Hibernate: alter table Customer_TBL_ORDER add constraint UK_sw94jktvh72tripj876s31052  unique (orders_id)
Hibernate: alter table Customer_TBL_ORDER add constraint FK_sw94jktvh72tripj876s31052 foreign key (orders_id) references TBL_ORDER
Hibernate: alter table Customer_TBL_ORDER add constraint FK_f03up2h945cg0dcbo2pdb1d3c foreign key (Customer_id) references Customer
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

Почему hibernate создает дополнительную таблицу в этом случае? Как атрибут mappedBy контролирует это? Почему у нас есть дополнительное уникальное ограничение ключа для столбца orders_id в таблице Customer_TBL_ORDER?

Теперь, если я попытаюсь сохранить клиента и его заказы, я получу ниже операций DML:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: insert into Customer_TBL_ORDER (Customer_id, orders_index, orders_id) values (?, ?, ?)

Почему у нас нет дополнительного запроса на обновление в этом случае по сравнению с тем случаем, когда я объявил атрибут mappedBy?

Ответ 1

Это нормальное.

С помощью mappedBy вы напрямую указываете Hibernate/JPA, что одна таблица владеет этим отношением и поэтому хранится в виде столбца этой таблицы.

Без этого отношения внешние, а Hibernate/JPA необходимо создать другую таблицу для хранения отношения.

Пример:

  • У stackoverflow Question есть несколько Answer.
  • An Answer принадлежит одному и только одному Question.

В простом JDBC вы создадите две таблицы:

Questions(Question_ID, ...);
Answers(Answer_ID, Question_ID, ...);

Где Question_ID - это внешний ключ, ссылающийся на Question.Question_ID.

Как и в другом случае, у меня нет реального случая, поскольку почти каждый раз многие из них имеют уникальное ограничение (например: a Question может иметь несколько Answer, а Answer может иметь физически имеют несколько Question, но отображаются только один раз для любого Question).

Ответ 2

A OneToMany имеет два основных способа, которыми это может быть достигнуто в базе данных.

  • с использованием таблицы отношений (M: M)
  • с использованием внешнего ключа в целевой таблице. (1: М)

Если вы оставите отображение OneToMany и зададите его по умолчанию, оно по умолчанию будет использовать таблицу отношений, которая, как вам кажется, вам нужна. Если вы не хотите использовать таблицу соединений, вы должны указать либо JoinColumn, который устанавливает отношение внешнего ключа, как и OneToOne, но в противоположном направлении - указывает провайдеру, какое поле в целевом таблица указывает на первичный ключ этого объекта. Но обычно целевой внешний ключ отображается в целевом объекте - он все равно ManyToOne - и поэтому mappedby используется для указания, что этот OneToMany должен использовать отношение, уже определенное в целевом объекте.

В этом случае mappedBy=customer говорит ему, чтобы посмотреть на отображение свойств customer в объекте Order. Там он находит, что клиент имеет сопоставление ManyToMany с по умолчанию joinColumn customer_id, которое он также использует для OneToMany. Поскольку он уже отображается в объекте Order, OneToMany доступен только для чтения. Это гарантирует, что если два отношения не синхронизируются, JPA имеет одну сторону, чтобы всегда доверять и использовать для установки поля базы данных.

Ответ 3

Нормально это поведение mappedBy указывает только на то, что объект в этой стороне является обратным отношению, а владелец находится в "другой" сущности.

Я предлагаю вам ссылку