Сохранение двунаправленного 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;
..
}