Hibernate - Many To Many хочет снова сохранить данные

У меня есть класс User, где я хочу, чтобы отношение ManyToMany ссылалось на себя - я решаю, что пользователь может следовать / следовать за другим пользователем. Нет необходимости в других атрибутах, поэтому это должна быть одна таблица с составным первичным ключом. Вот как это аннотируется:

@ManyToMany(cascade = {CascadeType.ALL, CascadeType.MERGE})
@JoinTable(name = "user_followers", joinColumns = { @JoinColumn(name = "follower") }, inverseJoinColumns = { @JoinColumn(name = "following") })
private Set<User> following = new HashSet<User>();

@ManyToMany(mappedBy = "following")
private Set<User> followers = new HashSet<User>();

Все нормально - таблица сформирована, ПК составной follower_following. Когда я сохраняю данные с первой попытки, это работает - выполняется инструкция вставки. НО во второй раз он все еще пытается вставить ранее выполненное отношение (очевидно, не то же самое), и я получаю:

Unexpected RuntimeException
Last cause: Duplicate entry 'follower-following' for key 'PRIMARY' 
// EDIT: There are correct FK keys instead of follower-following

Вот как я добавляю последователя и сохраняю пользователя:

if (!user.following.contains(toFollowUser)) {
   user.following.add(toFollowUser);
}

if (session.contains(user)) {
    session.persist(user);
} else {
    session.merge(user)
}
session.getTransaction().commit(); // HERE I get exception

С моей точки зрения, похоже, что Hibernate не видит, что предыдущее отношение было сохранено и записано в базу данных, и все еще пытается вставить новую запись, которая, конечно, попадает в дублированный ключ. Ты хоть представляешь, что я делаю не так?

Может быть несвязанным, но «if (session.contains (user) -> persist» неверно, если сеанс уже содержит объект, объект прикреплен, поэтому вам не нужно вызывать persist для него (простое изменение объекта вызовет изменения будут сброшены после вызова коммита). Кстати, что вы имеете в виду под первым и вторым разом? разными транзакциями? одной и той же транзакцией?

paranoidAndroid 23.06.2018 22:19

Это означает другую транзакцию, она разделяется HTTP-запросом (я использую Wicket). Первый выполняется и закрывается, затем следует второй.

user76316 24.06.2018 12:46
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
32
0

Другие вопросы по теме