みなさん、こんばんは、これがStackOverflowに関する私の最初の投稿です。私はごく最近、Java 6 EE、特にJSF 2.1フレームワークの一部としてJPAを紹介されましたが、今、私が理解してほしい奇妙な振る舞いに直面しています。私たちのプロジェクト(NetBeans 7.2を使用して開発)では、いくつかの1対多の関係があり、多対1の関係をナビゲートするのと同じ方法でそれらをナビゲートしたいと思います。実際には、代わりに、アプリケーションサーバー(Glassfish 3.1.2)を再起動した後でのみ、必要に応じて動作させることができます。さらに、この動作は次のデプロイメントまでしか持続しません。つまり、変更を適用するたびにGlassfishを再起動する必要があります...状況を理解するのに役立つコードの抜粋を次に示します。
これは、とりわけ、Eメールおよび電話との1対多の関係、およびAccountTypeとの多対1の関係を持つ主要なエンティティ(Person)を表します。
@Entity
public class Person implements Serializable {
//
//private non-collection fields including id
//
@OneToMany(mappedBy="person", fetch=FetchType.EAGER)
private Collection<Email> personEmails;
@OneToMany(mappedBy="person")
private Collection<Phone> personPhones;
@ManyToOne
private AccountType accountType;
//
// getter and setter, hashCode, isEqual and toString
//
}
そして、これらは電子メールです...
@Entity
public class Email implements Serializable {
//
//private non-collection fields including id
//
private String address;
@ManyToOne
private Person person;
//
// getter and setter, hashCode, isEqual and toString
//
}
... 電話 ...
@Entity
public class Phone implements Serializable {
//
//private non-collection fields including id
//
private String number;
@ManyToOne
private Person person;
//
// getter and setter, hashCode, isEqual and toString
//
}
...およびAccountType
@Entity
public class AccounType implements Serializable {
//
//private non-collection fields including id
//
private String name;
@OneToMany(mappedBy="accountType")
private Collection<Person> persons;
//
// getter and setter, hashCode, isEqual and toString
//
}
次に、Personの3つのフィールドが実際にどのようにフェッチされるかをテストするためのサンプルページを設定しました。
これはxhtmlページを表します...
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel value="forename" />
<h:outputLabel value="#{meBean.currentUser.forename}" />
<h:outputLabel value="emails" />
<h:outputLabel value="#{meBean.currentUser.personEmails.size()}" />
<h:outputLabel value="phones" />
<h:outputLabel value="#{meBean.currentUser.personPhones}" />
<h:outputLabel value="accountType" />
<h:outputLabel value="#{meBean.currentUser.accountType.name}" />
</h:panelGrid>
</h:form>
...そしてこれはコントローラー
@ManagedBean
@RequestScoped
public class MeBean {
@EJB
private PersonFacade personFacade;
private Person currentUser;
public MeBean() {
init();
}
@PostConstruct
private void init() {
// Hard-coding user details
try {
this.currentUser = this.personFacade.getFromUsername("user1");
this.currentUser.getPersonPhones().isEmpty();
} catch (Exception e) {
}
}
public Person getCurrentUser() {
return currentUser;
}
public void setCurrentUser(Person currentUser) {
this.currentUser = currentUser;
}
}
これで、アプリケーションサーバーを再起動した直後にページにアクセスした場合にのみ期待される結果が得られます。
forename Alice
emails 2
phones {[sums.groupa.entities.Phone[id=38]]}
accountType Student
何か(ビューを除く)を変更して保存すると、必然的なデプロイの後で、結果は異なります。
forename Alice
emails 0
phones {[]}
accountType Student
なぜそれが起こっているのですか、そしてどうすればそれを避けることができますか?
前もって感謝します。
AG
数人の寄稿者(迅速な返信に感謝したい)がPersonFacadeの実装を求めました。
public Person getFromUsername(String username)
{
try
{
Query q = em.createQuery("SELECT p FROM Person p LEFT JOIN FETCH p.personEmails WHERE UPPER(p.username) = :username");
q.setParameter("username", username.toUpperCase());
return (Person) q.getSingleResult();
}
catch (Exception ex)
{
Logger.getLogger(PersonFacade.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
As you can see I tried to use FETCH JOIN as suggested but the query is getting out too many results: it should fetch only one instance of Person representing Alice and containing two instances of Email in the personEmails field but I suspect it is getting two different instances of Person, each having a different instance of Email attached.
The original query was as follows:
SELECT p FROM Person p WHERE UPPER(p.username) = :username
Thanks again.
AG