Hibernate, OneToMany Каскадной добавление/удаление детей

Есть класс User:

@Entity
@Table(name = "users")
public class User implements Serializable, Annotation {

    @Id
    @GeneratedValue(generator = "system-uuid", strategy = GenerationType.IDENTITY)
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Column(name = "uuid", unique = true)
    protected String uuid;

    @Column(name = "username")
    protected String username;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.user", cascade = CascadeType.ALL)
    private Set<UserItem> userItems;
}


У него есть дети Set.

Класс UserItem:
@Entity
@Table(name = "user_item")
@AssociationOverrides({
        @AssociationOverride(name = "pk.user",
                joinColumns = @JoinColumn(name = "user_uuid")),
        @AssociationOverride(name = "pk.ItemShop",
                joinColumns = @JoinColumn(name = "item_shop_uuid")) })
public class UserItem implements Serializable {

    @EmbeddedId
    protected UserItemId pk = new UserItemId();

    @Transient
    public User getUser() {
        return getPk().getUser();
    }

    public void setUser(User user) {
        getPk().setUser(User);
    }

    @Transient
    public ItemShop getItemShop() {
        return getPk().getItemShop();
    }

    public void setItemShop(ItemShop ItemShop) {
        getPk().setItemShop(ItemShop);
    }
}


У сета useritem стоит тип каскадных операций "ALL" - то есть все изменения с полями класса User также отразятся на его детях. HIbernate пройдется по ним и применит все изменения.

Исполняем код добавления детеныша:

UserItem userItem = new UserItem();
userItem.setUser(user);
userItem.setItemShop(ItemShop);

user.getUserItems().add(userItem);
session.saveOrUpdate(user);
session.flush();


Детеныш добавится и в объект user и в базу данных. Если выполнить merge - детеныш добавится только в сущность - что есть правильно.

Удаляем детеныша:
Set<UserItem> userItems = user.getUserItems();
UserItem userItem = userDAO.findUserItem(user,  itemShop);
userItems.remove(userItem);
session.saveOrUpdate(user);
session.flush();

Получаем исключение:

org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.test.User#2d0767d8-effb-41f2-8910-5729a460527d]


Что я делаю не так? Откуда exception?

UPDATED:
Получил следующий рабочий код на удаление:
User user = UserDetails.getUser();
        Set<UserItem> userItems = user.getUserItems();
        UserItem userItem = UserDAO.findUserItem(user, itemShop);
        UserItems.remove(UserItem);
        session.merge(user);
        session.flush();
        session.clear();


Да только не чисто работает код, а суть в следующем, у юзера есть 3 Item, удаляю первый - мержу - все окей, удаляю второй - мержу - второй удаляется и вываливается exception, мол не могу добавить row - нет такой записи, то есть где то в кеше осталась запись о том первом item, который я удалил первый и hibernate попытался записать его в базу - что не есть правильно впринципе, и вообще merge это немного не решение моей проблемы.

Также я немного больше получил понимание по первому Exception'y:
org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.test.User#2d0767d8-effb-41f2-8910-5729a460527d]


Вся суть в том что, объект user - это залогиненный пользователь полученный при помощи собственной аннотации, которую я повесил на контроллер. То есть, в контроллере есть аннтотация которая получается залогиненного пользователя, естественно что она получает его при помощи hibernate (не явно конечно, долго объяснять, а код показываться - отклонятся от темы вопроса), так вот, полученный объект пользователя из контроллера я и передаю в метод удаления детеныша из родителя. То есть получается что hibernate видит в persistent сессии тот самый объект с 3 детьми, а тут я ему подсовываю другой объект с 2 детьми уже, а они по какой-то дикой причине разные!!! Я попробовал еще раз вытянуть из базы пользователя и у него удалить детеныша - удалилось, да только вот сущность которая представляет собой залогированного пользователя осталась неизменной.
  • Вопрос задан
  • 4982 просмотра
Пригласить эксперта
Ответы на вопрос 1
@bobzer
Java EE Developer
Похоже на то, что ошибка возникает из-за лишних манипуляций с сущностями. Посмотрите под отладкой содержимое сессии, в ней собирается список всех объектов, подлежащих сохранению при вызове flush/commit. Скорее всего, кроме явно видимой в коде сущности user, в сессии в какой-то момент (может, userDAO.findUserItem ?) появляется ещё один экземпляр User, например в UserItemId. Вам надо добиться того, чтобы все взаимосвязи ссылались на один и тот же экземпляр объекта. Для этого попытайтесь выполнять все операции в одной сессии, т.е., если в потоке выполнения кода уже открыта одна сессия, не открывать других сессий (в userDAO.findUserItem ?) пока не будет закрыта текущая сессия.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы