Сохранение двунаправленного ManyToMany

У меня есть два класса объектов, аннотированные следующим образом.

@Entity
class A {
   @ManyToMany(mappedBy="A", cascade=CascadeType.ALL)
   private List<B> b;
 ..
}

@Entity
class B {
   @ManyToMany(cascade=CascadeType.ALL)
   private List<A> a;
 ..
}

Если я храню экземпляр класса "B", отношения сохраняются в базе данных, а getter в классе "A" вернет правильное подмножество B. Однако, если я вношу изменения в список Bs в "A", изменения не сохраняются в базе данных?

Мой вопрос: как я могу сделать так, чтобы изменения в любом классе "каскадировались" в другой класс?

EDIT: я пробовал различные варианты удаления параметра mappedBy и определения JoinTable (и столбцов), но мне не удалось найти правильную комбинацию.

Ответ 1

Самый короткий ответ, похоже, вы не можете, и это имеет смысл. В двунаправленной связи "многие-ко-многим" одна сторона должна быть главной и используется для сохранения изменений в базовой таблице соединений. Поскольку JPA не будет поддерживать обе стороны ассоциации, вы можете столкнуться с ситуацией памяти, которую невозможно перезагрузить после сохранения в базе данных. Пример:

A a1 = new A();
A a2 = new A();
B b = new B();
a1.getB().add(b);
b.getA().add(a2);

Если это состояние может быть сохранено, в таблице соединений вы получите следующие записи:

a1_id, b_id
a2_id, b_id

Но после загрузки, как JPA знает, что вы намеревались только сообщить b о a2, а не a1? и как насчет a2, который не должен знать о b?

Вот почему вам нужно поддерживать двунаправленную ассоциацию самостоятельно (и сделать вышеприведенный пример невозможным, даже в памяти), и JPA будет сохраняться только на основе состояния одной из сторон.

Ответ 2

Вы указали столбцы обратного соединения?

@Entity
class A {
   @ManyToMany(mappedBy="A", cascade=CascadeType.ALL)
   private List <B> b;
   ..
}

@Entity 
class B { 
   @ManyToMany 
   @JoinTable (
       name="A_B",
       joinColumns = {@JoinColumn(name="A_ID")},
       inverseJoinColumns = {@JoinColumn(name="B_ID")}
   )
   private List<A> a; 
   .. 
} 

Предположим, что таблица соединений называется A_B со столбцами A_ID и B_ID.

Ответ 3

Поскольку отношение является двунаправленным, так как обновления приложений одна сторона отношений, другая сторона также должна обновляться, и быть в синхронизации. В JPA, как и в Java вообще , это ответственность приложения или объектная модель для поддержания отношения. Если ваше приложение добавляет одну сторону отношения, то он должен добавить к другой стороне.

Это можно решить путем добавления или установки методов в объектной модели которые обрабатывают обе стороны отношений, поэтому код приложения не нужно беспокоиться об этом. Есть два способа сделать это, вы можете либо добавить код обслуживания отношений в одну сторону от отношения, и использовать только сеттер с одной стороны (например, что делает другую сторону защищенной) или добавить ее на обе стороны и обеспечить вы избегаете бесконечного цикла.

Источник: OneToMany#Getters_and_Setters

Ответ 4

Пробовали ли вы добавить параметр mappedBy в поле A в классе B, например,

@Entity
class B {
   @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b")
   private List<A> a;
 ..
}

Ответ 5

Возможно, в ответе A_M есть небольшая ошибка. По-моему, это должно быть:

   @Entity
   class B { 
   @ManyToMany 
   @JoinTable (
       name="A_B",
       joinColumns = {@JoinColumn(name="B_ID")},
       inverseJoinColumns = {@JoinColumn(name="A_ID")}
   )
   private List a; 
   .. 
}