Отношение многие ко многим для объекта одного типа
У меня есть сущность, как показано ниже. Мне любопытно, возможно ли создать отношения, как я буду описывать на примере:
- Я создаю 2 лица сущностей Майкла и Юлию.
- Я добавляю Джулию в набор друзей Майкла.
После этого я получаю Майкла как ответ JSON, а Джулия доступна в ответе. Но когда я забираю Джулию, набор ее друзей пуст. Я хочу создать двустороннюю дружескую связь, сохранив только одну сторону дружбы. Я хотел бы пригласить Майкла на съемочную площадку друзей Юлии, не делая никаких других операций. Я думаю, что этим должен управлять Hibernate. Возможно ли это и как мне это сделать?
@ToString(exclude = "friends") // EDIT: these 2 exclusion necessary @EqualsAndHashCode(exclude = "friends") public class Person{ @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; @Column(name = "name",unique = true) private String name; @JsonIgnoreProperties("friends") // EDIT: will prevent the infinite recursion @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "FRIENDSHIP", joinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "friend_id", referencedColumnName = "id")) private Set<Person> friends;
Вот мой код уровня сервиса для создания дружбы:
@Override
public Person addFriend(String personName, String friendName)
throws FriendshipExistsException, PersonNotFoundException {
Person person = retrieveWithName(personName);
Person friend = retrieveWithName(friendName);
if(!person.getFriends().contains(friend)){
person.getFriends().add(friend);
return repository.save(person);
}
else{
throw new FriendshipExistsException(personName, friendName);
}
}
Смежный вопрос: N + 1 запрос двунаправленного "многие ко многим" для одного и того же типа объекта
Обновлен исходный код, и эта версия работает правильно.
1 ответ
// Creating a graph to help hibernate to create a query with outer join.
@NamedEntityGraph(name="graph.Person.friends",
attributeNodes = @NamedAttributeNode(value = "friends"))
class Person {}
interface PersonRepository extends JpaRepository<Person, Long> {
// using the named graph, it will fetch all friends in same query
@Override
@EntityGraph(value="graph.Person.friends")
Person findOne(Long id);
}
@Override
public Person addFriend(String personName, String friendName)
throws FriendshipExistsException, PersonNotFoundException {
Person person = retrieveWithName(personName);
Person friend = retrieveWithName(friendName);
if(!person.getFriends().contains(friend)){
person.getFriends().add(friend);
friend.getFriends().add(person); // need to setup the relation
return repository.save(person); // only one save method is used, it saves friends with cascade
} else {
throw new FriendshipExistsException(personName, friendName);
}
}
Если вы проверите свои журналы гибернации, вы увидите:
Hibernate: вставьте в личную (имя, идентификатор) значения (?,?)
Hibernate: вставьте в личную (имя, идентификатор) значения (?,?)
Hibernate: вставить в дружбу (person_id, friend_id) значения (?,?)
Hibernate: вставить в дружбу (person_id, friend_id) значения (?,?)