同様の質問に関する多くの記事と回答を読みましたが、まだ理解できません。
ここに私の親クラス:
@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;
}
ここでは、Items と Friends of User の 2 つのセットを確認できます。
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にあることを理解しています-休止状態は私が望むことを実行できないため、これはこれに最適なバリアントではありません-ユーザーは永続オブジェクトであり、永続的な新しいアイテムに追加してデータベースに保存するだけであることを理解してください。親クラス(ユーザー)と子(アイテム)があり、新しいアイテムを追加して親からアイテムを削除してデータベースに保存したい場合、この状況で勝つためのベストプラクティスは何ですか。実際、私は(イテレータを使用して)作業方法を見つけましたが、高負荷プロジェクトでは、そのような操作のループを作成する最悪のバリアントであることを理解しています。そのような状況のベストプラクティスを見つけたいと思っています。
質問の更新: 私は間違いを犯しました。セットに子を追加するコードを呼び出すと(上記のコード)-すべて問題ありません-データベースとエンティティに子が追加されましたが、子を削除しようとすると:
Set<UserItem> userItems = user.getUserItems();
UserItem userItem = userDAO.findUserItem(user, itemShop);
userItems.remove(userItem);
session.saveOrUpdate(user);
session.flush();
それから私は例外を得ました:
org.hibernate.NonUniqueObjectException: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられています
もう1つの更新:
多くの実験の後、アイテムを追加する作業コードを取得しました:
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つのアイテムを持っています。アイテムを 1 つ削除します。すべて問題ありません。後で、もう 1 つのアイテムを削除しようとすると、休止状態に次のように表示されます。
ObjectNotFoundException: 指定された識別子を持つ行が存在しません
つまり、キャッシュにはまだ3つのアイテムがあります-最初に削除したアイテム-キャッシュと休止状態にまだあり、データベースに追加しようとしていますが、削除されています。
そして、この質問に答えるのに役立つもう 1 つのマインド アイデアがあります。オブジェクト ユーザー - 子を削除しようとしている場所 - SecurityContext からログに記録されたユーザーです - コントローラーから取得しました - コントローラーには、ユーザーがセキュリティから取得した場所に注釈があります。そのため、休止状態には既にキャッシュに記録されたユーザー (User オブジェクト) があります。何か案は?