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

相关问题