2013-03-11 42 views
0

大家晚上好,這是我在Stack Overflow上的第一篇文章。 我最近已經介紹了Java 6 EE,特別是JPA作爲JSF 2.1框架的一部分,現在我正面臨一個奇怪的行爲,我希望你能幫助我理解。 在我們的項目中(使用NetBeans 7.2開發的),我們有幾個一對多的關係,我們希望按照我們導航多對一的方式導航它們。事實上,我們只能在重新啓動應用服務器(GlassFish 3.1.2)後才能使其工作,並且此行爲僅在下一次部署之前持續;這意味着我們需要在每次應用修改時重新啓動Glassfish ... 以下是一些代碼摘錄,可幫助您瞭解我們的情況。JPA EAGER fetch只在服務器重啓時才起作用

這代表我們的主要實體(人)有,其他人之中,與電子郵件以及與電話,並與ACCOUNTTYPE

@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中的這三個字段是如何被實際獲取的。

這代表了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; 
     } 
    } 

正如你可以看到我試圖用fetch連接的建議,但查詢走出了太多的結果:它應該只獲取一個人物代表Alice和含在personEmails場電子郵件的兩個實例,實例,但我懷疑它得到了兩個不同的Person實例,每個實例都有一個不同的Email實例。

原始查詢如下:再次

SELECT p FROM Person p WHERE UPPER(p.username) = :username 

感謝。

AG

+0

什麼隱藏在「如果我們修改任何東西」後面?你有什麼修改和如何?外觀如何得到人並返回? – 2013-03-11 21:38:57

+0

我的意圖是「如果我們修改任何東西」,實際上是對託管的bean,會話bean,實體bean或外牆進行的每一項修改。這會導致NetBeans重新部署項目,並由於某些原因「使無效」的渴望獲取類型。關於如何實施門面,我將編輯帖子。謝謝 – algu84 2013-03-12 15:06:55

回答

0

我不知道你是怎麼寫你的personFacade,並得到了Person實體。

但我想你使用查詢。

如果您正在使用JPQL,請嘗試抓取連接。

+0

是否需要JPQL?我會認爲FetchType.EAGER會排序嗎? (儘管如此,FetchType.LAZY也是如此。) – Bridgey 2013-03-11 21:39:24

+0

JPQL不是必需的。我相信使用find()會給你你想要的行爲。 我的意思是,如果您使用JPQL,請嘗試抓取。 – 2013-03-11 22:16:04

+0

我已經嘗試了Tony Lang的建議,但是如果我已經在JPQL查詢中正確使用了「FETCH JOIN」,它會得到太多的結果。謝謝 – algu84 2013-03-12 15:10:08

相關問題