User と UserGroup という典型的な 2 つのエンティティを持つアプリケーションを作成しています。後者には、前者のインスタンスが 1 つ以上含まれる場合があります。そのために次の(多かれ少なかれ)マッピングがあります:
ユーザー:
public class User {
@Id
@GeneratedValue
private long id;
@ManyToOne(cascade = {CascadeType.MERGE})
@JoinColumn(name="GROUP_ID")
private UserGroup group;
public UserGroup getGroup() {
return group;
}
public void setGroup(UserGroup group) {
this.group = group;
}
}
ユーザー・グループ:
public class UserGroup {
@Id
@GeneratedValue
private long id;
@OneToMany(mappedBy="group", cascade = {CascadeType.REMOVE}, targetEntity = User.class)
private Set<User> users;
public void setUsers(Set<User> users) {
this.users = users;
}
}
これで、これらのエンティティ (UserDao と UserGroupDao) ごとに個別の DAO クラスができました。私のすべての DAO には、次のように @PersistenceContext アノテーションを使用して EntityManager が挿入されています。
@Transactional
public class SomeDao<T> {
private Class<T> persistentClass;
@PersistenceContext
private EntityManager em;
public T findById(long id) {
return em.find(persistentClass, id);
}
public void save(T entity) {
em.persist(entity);
}
}
このレイアウトを使用して、新しいユーザーを作成し、既存のユーザー グループに割り当てます。私はこのようにします:
UserGroup ug = userGroupDao.findById(1);
User u = new User();
u.setName("john");
u.setGroup(ug);
userDao.save(u);
残念ながら、次の例外が発生します。
オブジェクトが保存されていない一時インスタンスを参照しています - フラッシュする前に一時インスタンスを保存します: xyzmodel.User.group -> xyzmodel.UserGroup
私はそれを調査しましたが、各DAOインスタンスに異なるentityManagerが割り当てられており(各DAOのエンティティマネージャーへの参照が異なることを確認しました)、ユーザーのentityManagerが渡されたUserGroupインスタンスを管理していないために発生すると思います。
ユーザーに割り当てられたユーザー グループを UserDAO のエンティティ マネージャーにマージしようとしました。これには 2 つの問題があります。
- それでも機能しません-エンティティマネージャーは既存のユーザーグループを上書きしようとしており、例外が発生します(明らかに)
- うまくいったとしても、関連するエンティティごとにマージコードを書くことになります
説明されているケースは、検索と永続化の両方が同じエンティティ マネージャーを使用して行われる場合に機能します。これは質問を指します:
- 私のデザインは壊れていますか?この回答で推奨されているものとかなり似ていると思います。すべての DAO に対して単一の EntityManager が存在する必要がありますか (Web はそうではないと主張しています)。
- または、グループの割り当ては DAO 内で行う必要がありますか? この場合、DAO に多くのコードを書くことになります。
- DAO を削除する必要がありますか? はいの場合、データ アクセスを適切に処理するにはどうすればよいですか?
- 他の解決策はありますか?
Spring をコンテナーとして使用し、Hibernate を JPA 実装として使用しています。