java - Hibernate 一对多添加新子项

标签 java hibernate persistent hibernate-cascade

我读了很多类似问题的文章和答案,但还是看不懂。

这是我的父类:

@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: A different object with the same identifier value was already associated with the session

我知道主要问题是在 CascadeTypes 中 - 所有这都不是最好的变体,因为 hibernate 无法执行我想要的操作 - 了解 User 是一个持久对象,只需添加到持久新项目并将其保存到数据库。所以我想问你,当我有父类(用户)和子类(项目)并且我想添加新项目并从父类中删除项目并将其保存到数据库时,在这种情况下获胜的最佳实践是什么。事实上,我找到了工作方法(使用迭代器),但我知道在高负载项目中,它是此类操作的最糟糕的 for 循环变体。我真的很想找到针对这种情况的最佳实践。

问题更新: 我犯了错误。当我调用执行添加子项设置的代码(上面的代码)时 - 一切都很好 - 子项添加到数据库和实体中,但是当我尝试删除子项时:

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

再次更新:

经过大量实验,我得到了添加项目的工作代码:

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 个项目。我删除了一项 - 一切都很好。后来我尝试再删除一项,hibernate 告诉我:

ObjectNotFoundException: No row with the given identifier exists

这意味着在缓存中仍然有 3 个项目 - 我首先删除的一个 - 仍然在缓存中并且 hibernate 尝试将其添加到数据库中 - 但它被删除了。

我还有一个想法,可以帮助我们回答这个问题。对象用户 - 我试图删除子项 - 它是从 SecurityContext 记录的用户 - 我从 Controller 获得它 - Controller 具有用户从安全处获得的注释。所以,hibernate已经在缓存中记录了用户(User对象)。有什么想法吗?

最佳答案

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();

如果其中任何一个没有意义,请告诉我。

附录:OP 正在其 Controller 内获取用户的持久实例,但没有对其执行任何操作。这导致 Hibernate 抛出 NonUniqueObjectException

关于java - Hibernate 一对多添加新子项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24225264/

相关文章:

100 个用户的 JAVA MYSQL 聊天性能问题

java - java中的数据报

java - 将 JPA 对象转换为 XML/JAXB

java - 创建自定义 hibernate 查询

php - 如何防止 SQLITE SQLSTATE[HY000] [14]?

haskell - Yesod/persistent 中的 SQL View

java - 如何在tomcat中标记JSESSIONID安全?

java - 为什么我在 Hibernate 中遇到错误?

java - 每次构建应用程序时,netbeans 中的 MySQL 表都会被清除

java - 在 onCreate 方法中传递 Activity 上下文