あらゆる種類のエンティティのリスト プロパティで「奇妙な」動作をします。
null のリスト値を持つ取得されたエンティティに空でないリストを設定しようとすると (フェッチされないため)、エンティティは設定した新しい空でない値を「反映」しません。
手順
- 条件付きの EJB でデータベースから任意のエンティティ (ユーザーなど) を取得します。
- 取得されたエンティティには、デフォルトで OneToMany 属性 (ロール) があります。これは、フェッチを行わない (行わない) 場合、リストが null になる理由です。
- 次に、役割リストに空でないリストを入力してみてください
- ここで設定したリストには値がありますが、ステップ 3 で設定したにもかかわらず、ユーザー リストのロール リスト属性に null があります。
なぜこれが起こっているのかわかりません。これを修正できる唯一の方法は、(Apache commons.lang3 の SerializationUtils を使用して) ユーザー エンティティを複製し (手順を参照)、この作業を行うことですが、理由はわかりません。
- 条件付きの EJB でデータベースから任意のエンティティ (ユーザーなど) を取得します。
- 取得したエンティティを複製し、新しいユーザーに割り当てます。 clonedUser = SerializationUtils.clone(originalRetrivedUser);
- 次に、役割リストに空でないリストを clonedUser に入力してみてください
- clonedUser のリストには正しい値があります
なぜクローンを作成する必要があるのですか? エンティティが複製されていない場合、エンティティにリストを設定できないのはなぜですか?
私はApache TomEE 1.6.0-SNAPSHOTを使用しています(openjpaバージョンが埋め込まれています)
***** ENTITIES *****
@Entity
public class User implements Serializable{
@Id
private int id;
private String userName;
private String password;
@OneToMany(mappedBy = "user")
private List<Role> roles;
//getters and setters..
}
@Entity
public class Role implements Serializable{
@Id
private int id;
private String roleName;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
//getters and setters..
}
**** EJB INTERFACE LOCAL ****
@Local
public interface MyEJBLocal{
public User getUserWithRoles();
}
**** EJB CLASS ****
@Stateless
public class MyEJB implements MyEJBLocal{
@PersistenceContext(unitName ="ANY_NAME")
private EntityManager em;
@Override
public User getUserWithRoles(){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class);
cq.where(cb.equal(root.get(User_.userName),"john"));
User userJohn = em.createQuery(cq).getSingleResult(); // if I want this work I have to do User userJohn = SerializationUtils.clone(em.createQuery(cq).getSingleResult()); [1*]
//I will create a list of role just for try to set any role the userJohn
List<Role> roleList = new ArrayList<Role>(2);
roleList.add(new Role(1,'ADMIN'); //creating and adding role 1
roleList.add(new Role(2,'DEVELOPER');//creating and adding role 2
//setting the list of roles created to the user, as you can see the list has 2 values but the value roles of userJohn always is set to null, my setters and getters are correct
userJohn.setRoles(roleList);
return userJohn;
}
}
*** MANAGED BEAN ****
@Named
public class MyBean implements Serializable{
@EJB
private MyEJBLocal ejb;
public void anyMethod(){
User user = ejb.getUserWithRoles();
user.getRoles(); //<---- HERE THE LIST IS ALWAYS NULL but if I use clone in the ejb method (see 1*) I can get the corrected values.
}
}
フェッチすることで値を取得できることはわかっていますが、そうしないようにしています。
前の例では、リストを ejb に設定しようとしましたが、リストを削除してマネージド Bean に配置すると、同じ動作が得られます。
エンティティを取得して情報を追加したいだけですが、その新しい情報を保持したくありません。
detach メソッドを使用しようとしていますが、何も変わりません。
@Transient を使用したくないのは、データを永続化する必要がある場合があるためです。アイデアは簡単です。エンティティを取得したい場合は、マネージド Bean で新しいリストを追加したいのですが、リストに何を設定しても (エンティティ (ユーザー) のロール) エンティティのリストは、エンティティのリストが何らかの方法で保護されている場合と同様に、常に null に設定されます。