2009-05-05 4 views
10

У меня есть два класса объектов аннотированных следующим образомСохранение двунаправленной 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», отношения сохраняются в базе данных и геттер в классе «А» вернет правильное подмножество B. Однако, если я вношу изменения в список Bs в «A», изменения не сохраняются в базе данных?

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

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

+0

Какие реализации JPA вы используете? –

ответ

16

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

0

Вы судимое добавления параметра mappedBy на поле в классе В, как так

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

Это не сработает, это означает незаконную параметризацию. Параметр mappedBy определяет право собственности на поле, и поэтому использование этого параметра для обеих коллекций невозможно, поскольку они не могут принадлежать друг другу. –

3

уточнили вы обратные столбцы?

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

+0

Я тоже пробовал это решение, но не повезло :( –

+2

shouldn "t mappedBy равен« a »в нижнем регистре вместо класса? – Ced

0

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

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

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

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

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

Смежные вопросы