我已经阅读了很多关于类似问题的文章和答案,但我仍然无法理解。
这是我的父类:
@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 - 所有它不是最好的变种,因为hibernate不能做我想要的 - 理解User是一个持久对象,只是添加到持久性新项目并将其保存到数据库。所以我想问你,在这种情况下获胜的最佳做法是什么,当我有父类(用户)和子(项目)时,我想添加新项目并从父项中删除项目并将其保存到数据库。事实上,我找到了工作方法(使用迭代器),但我明白在高负载项目中,这是对这种操作进行循环的最差变量。我真的想找到适合这种情况的最佳做法。
问题更新: 我犯了错误。当我调用执行添加子设置的代码(上面的代码) - 一切都很好 - 孩子在数据库和实体中添加,但是当我试图删除孩子时:
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);
它是Service层中向用户添加项的方法代码。它正在发挥作用。我有半工作代码从用户删除项目:
Set<UserItem> userItems = user.getuserItems();
UserItem userItem = UserDAO.findUserItem(user, itemShop);
userItems.remove(userItem);
userDAO.merge(user);
代码不正确。我们有一个情况 - 用户有3个项目。我删除了一个项目 - 一切都很好。后来我试图再删除一个项目,hibernate说我:
ObjectNotFoundException:不存在具有给定标识符的行
这意味着在缓存中还有3个项目 - 我首先删除 - 仍然在缓存中,而hibernate尝试将其添加到数据库中 - 但它被删除。
我还有一个想法,这可以帮助我们回答这个问题。对象用户 - 我试图删除孩子 - 它是来自SecurityContext的登录用户 - 我是从控制器获得的 - 控制器具有用户从安全获取的注释。因此,hibernate已经在缓存记录用户(User对象)中。有什么想法吗?
答案 0 :(得分:2)
OP必须手动管理有效的连接表,因为连接表上还有额外的字段需要进行管理。尝试从用户删除项目对象时,这会导致问题。
当我必须明确地管理连接或者我有连接附加的额外信息时,这是我设置多对多的标准方法。如果我没有任何额外信息,或者不必自己管理加入,只需使用@JoinTable注释。
新对象:
@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 userUUID;
@Column(name = "username")
protected String username;
@OneToMany(mappedBy="user", cascade = CascadeType.ALL, orphanRemoval=true)
private Set<UserItem> items = new HashSet<UserItem>();
}
物品对象:
@Entity
@Table(name="items")
public class Item implements Serializable{
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2")
@Column(name = "uuid", unique = true)
protected String itemUUID;
@Column(name = "name")
protected String name;
@Column(name = "description")
protected String description;
@OneToMany(mappedBy="item", cascade = CascadeType.ALL, orphanRemoval=true)
private Set<UserItem> users = new HashSet<UserItem>();
UserItem类:
@Entity
@Table(name = "user_item")
public class UserItem implements Serializable {
//Generate this like you are doing with your others.
private String userItemUUID;
@ManyToOne
@JoinColumn(name="userUUID")
private User user;
@ManyToOne
@JoinColumn(name="itemUUID")
private Item item;
private BigDecimal moneyCollect;
private Date dateAdded = new Date();
}
您要删除的服务如下所示:
UserItem userItem = userDAO.findUserItem(user, itemShop);
user.getUserItems().remove(userItem);
session.saveOrUpdate(user);
session.flush();
你也可以采用其他方式。
UserItem userItem = userDAO.findUserItem(user, itemShop);
item.getUserItems().remove(userItem);
session.saveOrUpdate(item);
session.flush();
您获得的异常是由Hibernate在方法中发现两个UserItem
对象引起的,这两个对象都是持久的,不知道要删除哪个。
//Create one UserItem instance here
Set<UserItem> userItems = user.getUserItems();
//Create another UserItem instance here
UserItem userItem = userDAO.findUserItem(user, itemShop);
userItems.remove(userItem);
//Hibernate doesn't know which UserItem instance to remove, and throws an exception.
session.saveOrUpdate(user);
session.flush();
如果其中任何一项没有意义,请告诉我。
ADDENDUM:OP在他们的控制器中获得了一个持久的User实例,并且没有对它做任何事情。这导致了Hibernate抛出的NonUniqueObjectException
。