- - PR -
EJB3.0で、関連先がインスタンス化されない
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2008-12-16 17:20
EJB3.0の動作がよく分からないので質問させてください。
Person--->Group という2つのEntityがあります。 Queryを使ってPersonを検索すると、正しく見つかりますが、 Personの属性groupが常にnullです。 一旦Groupの全検索を行い、その後でPersonを検索すると属性groupに値が入っています。 つまり、関連をたどってEntityのインスタンス化をしてくれないのです。 サンプルなどを見ると、きちんとインスタンス化してくれるようだし、 @JoinColumn(name="GROUP_ID0", referencedColumnName="GROUP_ID",nullable=false) のreferencedColumnNameを変更するとエラーが返るので、Groupの検索SQLは実行されているようなのです・・・ ( SELECT GROUP_ID,GROUP_NAME FROM GROUPS WHERE (GROUP_ID0=?) のようなsqlがエラーに吐かれます) しかし、Groupはnullです。 考えられる理由、調査方法などあれば教えてください。 環境は、 NetBeans6.5 GlassFish-v2 TopLink-essentials Oracle10g です。 |
|
投稿日時: 2008-12-17 09:39
たとえば
Person { @OneToOne(mappedBy="group",fetch=FetchType.LAZY,name=.. @JoinColumn... Group getGroup() } Group { @OneToOne @JoinColumn(.. Group getPerson() } としているとか? やったことないですが、JoinColumnは mappedByされるほうだけの1つですむので もう1つのColumnは設定されないとかあるかも。 |
|
投稿日時: 2008-12-17 10:33
<Personの一部>
@Entity @Table(name="USERS") @NamedQuery(name="findByLastname" ,query="select e from Person e where e.lastname = :lastname") public class Person implements Serializable{ @Id @Column(name="USER_ID") private String id; @Column(name="LAST_NAME") private String lastname; @Column(name="FIRST_NAME") private String firstname; @Column(name="MAIL_ADDRESS") private String mail; @ManyToOne @JoinColumn(name="GROUP_ID0", referencedColumnName="GROUP_ID",nullable=false) private Group group; <Groupの一部> @Entity @Table(name="GROUPS") public class Group implements Serializable{ @Id @Column(name="GROUP_ID") private String id; @Column(name="GROUP_NAME") private String name; こんな感じです。 少し調べたのですが、EAGERフェッチされないのが原因ぽいです。なぜでしょうか。 |
|
投稿日時: 2008-12-17 12:01
書き方が間違っていたのかはすぐにわかりませんが、単に@OneToManyを入れてないだけでは?
@Entity @Table(name="USERS") public class Person implements Serializable{ @Id @Column(name="USER_ID") private String id; .. [明らかな間違いを修正] @ManyToOne(fetch=FetchType.LAZY, optional=false) @JoinColumn(name="GROUP_ID0", nullable=false) private Group group; // ↑publicにしなくてよかったんでしたっけ? .. @Entity @Table(name="GROUPS") public class Group implements Serializable{ @Id @Column(name="GROUP_ID") private String id; @Column(name="GROUP_NAME") private String name; @OneToMany(mappedBy="group") private Collection<Person> persons; .. [ メッセージ編集済み 編集者: だっちょ 編集日時 2008-12-17 15:46 ] |
|
投稿日時: 2008-12-17 16:17
<Person>
@Entity @Table(name="USERS") @NamedQuery(name="findByLastname" ,query="select e from Person e where e.lastname = :lastname") public class Person implements Serializable{ @Id @Column(name="USER_ID") private String id; @Column(name="LAST_NAME") private String lastname; @Column(name="FIRST_NAME") private String firstname; @Column(name="MAIL_ADDRESS") private String mail; @ManyToOne(fetch=FetchType.EAGER, optional=false) @JoinColumn(name="GROUP_ID0", referencedColumnName="GROUP_ID",nullable=false) private Group group; <Group> @Entity @Table(name="GROUPS") public class Group implements Serializable{ @Id @Column(name="GROUP_ID") private String id; @Column(name="GROUP_NAME") private String name; @OneToMany(mappedBy="group") private Collection<Person> persons = new LinkedList<Person>(); 試しにこのように変えてみましたが、やはりGroupはnullのままでした。 SessionBeanの検索メソッドの中で、 for(Person p : persons) p.getGroup(); とやると、groupが入る事は確認できましたので、やはりgroupのフェッチをする前に EntityがWEB層に出て行ってしまっていることが原因のようです。 EAGERだと、Personオブジェクトを作ったときに同時にGroupもフェッチしてくれるのではないのでしょうか・・・ |
|
投稿日時: 2008-12-17 17:23
>EntityがWEB層に出て行ってしまっていることが原因のようです。
ひょっとしてEJBのインタフェースでEntityオブジェクトを返していて、 それをWeb層で見るとリレーションがクリアされているという話なのでしょうか? そうだとすると、Entityオブジェクトをそのまま返すインタフェースにしているのがまずいと思います。リレーション情報は単純にはインタフェースで復帰させることはできなかったはず。 そうでなければ下記と同様のコードでセッションBeanでデータを取得する限り問題はなかったと記憶していますので、私はこれ以上力になれそうもありません。 |
|
投稿日時: 2008-12-17 21:07
>ひょっとしてEJBのインタフェースでEntityオブジェクトを返していて、
>それをWeb層で見るとリレーションがクリアされているという話なのでしょうか? はい。おっしゃるとおりです。 >そうだとすると、Entityオブジェクトをそのまま返すインタフェースにしているのがまずいと思います。リレーション情報は単純にはインタフェースで復帰させることはできなかったはず。 >そうでなければ下記と同様のコードでセッションBeanでデータを取得する限り問題はなかったと記憶していますので、私はこれ以上力になれそうもありません。 ServletはPersonをダイレクトに参照しています。 確かに、そのままServletにEntityを返すと、EntityManagerの支配下から離れてDetatched?になるようですが、 そもそも最初のquery("findByLastname")を実行したと同時にGroupもフェッチしてくれればdetatchedになっても問題ないと 思うのです。 EAGERフェッチというのは、そういう意味ではないのでしょうか? LAZYフェッチは、必要なときにフェッチすると言う事なので、必要なときにdetatchedだと検索できないのは理解できます。 しかしEAGERなら・・・ |
|
投稿日時: 2008-12-18 09:22
EJBで復帰するObjectはたとえLocalであっても元のObjectではありません。リモートインタフェースに変更できることを考えると別サーバのObjectにそのままアクセスできないとわかると思います。
基本的なObjectは復元されますが、リレーション先までは復元されないためそのままでは取得できません。仮にリレーション先を復元した場合、極端なことをいれば1つのEntityを取得するのにDB全部を復元するような事態がありえるでしょう。 なので、リレーション先のデータを取得する場合はEJBのインタフェースを考える必要があります。リレーション先のデータを取得するインタフェースを追加してもいいですが、私の場合、EntityクラスがimplementするインタフェースでIDリストを返すようにしておき、XMLにmarhalしてインタフェースのObjectを復元するようにしてます。復元したEntityのリレーションはそのIDリストからIDで取得するようにしています。 |