Сохранение двунаправленной ManyToMany - PullRequest
11 голосов
/ 05 мая 2009

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

@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', отношения сохранятся в базе данных, и получатель в классе 'A' вернет правильное подмножество B. Однако, если я внесу изменения в список B в «A», изменения не сохранятся в базе данных?

У меня вопрос: как я могу сделать так, чтобы изменения в одном классе были «каскадными» к другому классу?

РЕДАКТИРОВАТЬ: я пробовал разные варианты удаления параметра mappedBy и определения JoinTable (и столбцов), но я не смог найти правильную комбинацию.

Ответы [ 5 ]

16 голосов
/ 22 мая 2009

Самый короткий ответ, кажется, вы не можете, и это имеет смысл. В двунаправленной ассоциации «многие ко многим» одна сторона должна быть главной и использоваться для сохранения изменений в базовой таблице соединений. Поскольку 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? а как насчет а2, который не должен знать о б?

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

3 голосов
/ 05 мая 2009

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

@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.

1 голос
/ 25 августа 2012

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

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

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

0 голосов
/ 27 апреля 2010

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

   @Entity
   class B { 
   @ManyToMany 
   @JoinTable (
       name="A_B",
       joinColumns = {@JoinColumn(name="B_ID")},
       inverseJoinColumns = {@JoinColumn(name="A_ID")}
   )
   private List a; 
   .. 
}
0 голосов
/ 05 мая 2009

Вы пробовали добавить параметр mappedBy в поле A в классе B следующим образом

@Entity
class B {
   @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b")
   private List<A> a;
 ..
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...