Прочитал много статей и ответов на подобные вопросы, но так и не могу понять.
Здесь мой родительский класс:
@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;
}
Здесь мы видим два набора - Предметы и Друзья пользователя.
Пример класса UserItemId:
@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);
}
}
И теперь я пытаюсь добавить новый элемент пользователю:
/*
'user' in this code i got from SecurityContext in controller
and I give it as parameter from controller to method (service layer) which can add new Item to user.
So user it is entity which already exists in database - it is logged user
*/
UserItem userItem = new UserItem();
userItem.setUser(user);
userItem.setItemShop(ItemShop);
user.getUserItems().add(userItem);
session.saveOrUpdate(user);
Но я получил ошибку:
org.hibernate.NonUniqueObjectException: другой объект с тем же значением идентификатора уже был связан с сеансом
Я понимаю, что основная проблема заключается в CascadeTypes - ВСЕ это не лучший вариант для этого, потому что спящий режим не может делать то, что я хочу - понять, что пользователь является постоянным объектом, и просто добавить в постоянный новый элемент и сохранить его в базе данных. Поэтому я хочу спросить вас, как лучше всего победить в этой ситуации, когда у меня есть родительский класс (пользователь) и дочерние элементы (элементы), и я хочу добавить новые элементы и удалить элементы из родительского и сохранить их в базу данных. Действительно, я нашел рабочий метод (используя итератор), но я понимаю, что на проекте с высокой нагрузкой это худший вариант make for loop для таких операций. Я действительно хочу найти лучшие практики для таких ситуаций.
ОБНОВЛЕНИЕ ВОПРОСА: я допустил ошибку. Когда я вызываю код, который выполняет добавление дочернего элемента в набор (код выше) - все хорошо - дочерний элемент добавляется в базу данных и в сущность, но когда я пытаюсь удалить дочерний элемент:
Set<UserItem> userItems = user.getUserItems();
UserItem userItem = userDAO.findUserItem(user, itemShop);
userItems.remove(userItem);
session.saveOrUpdate(user);
session.flush();
Затем я получил исключение:
org.hibernate.NonUniqueObjectException: другой объект с тем же значением идентификатора уже был связан с сеансом
ЕЩЕ ОДНО ОБНОВЛЕНИЕ:
После многих экспериментов я получил рабочий код добавления элемента:
UserItem userItem = new UserItem();
userItem.setUser(user);
userItem.setItemShop(ItemShop);
user.getUserItems().add(userItem);
session.saveOrUpdate(user);
Это код метода на уровне службы, который добавляет элемент пользователю. И это работает. И у меня есть полурабочий код для удаления элемента от пользователя:
Set<UserItem> userItems = user.getuserItems();
UserItem userItem = UserDAO.findUserItem(user, itemShop);
userItems.remove(userItem);
userDAO.merge(user);
Это не правильно работает код. У нас есть ситуация - у пользователя есть 3 элемента. Удаляю один пункт - все нормально. Позже я пытаюсь удалить еще один элемент, и спящий режим говорит мне:
ObjectNotFoundException: строки с данным идентификатором не существует
Это означает, что в кеше все еще 3 элемента - тот, который я удаляю первым - все еще в кеше, и спящий режим пытается добавить его в базу данных, но он удаляется.
И у меня появилась еще одна мысль, которая может помочь нам ответить на этот вопрос. Пользователь объекта - где я пытаюсь удалить дочерний элемент - это зарегистрированный пользователь из SecurityContext - я получил его от контроллера - у контроллера есть аннотация, где пользователь получил от безопасности. Итак, спящий режим уже имеет в кеше зарегистрированного пользователя (объект пользователя). Есть идеи?