JPA EAGER выборка работает только при перезапуске сервера

Добрый вечер всем, это мой первый пост о переполнении стека. Я совсем недавно познакомился с Java 6 EE и, в частности, с JPA как часть инфраструктуры JSF 2.1, и теперь я сталкиваюсь со странным поведением, которое я хотел бы, чтобы вы помогли мне понять. В нашем проекте (разработанном с использованием NetBeans 7.2) у нас есть несколько отношений один-ко-многим, и мы хотели бы перемещаться по ним так же, как и по многим-одному. Дело в том, что вместо этого мы можем заставить их работать так, как нам хочется, только после перезапуска сервера приложений (Glassfish 3.1.2), и, кроме того, такое поведение сохраняется только до следующего развертывания; Это означает, что нам нужно перезапускать Glassfish каждый раз, когда мы применяем модификацию... Вот некоторые выдержки из кода, которые помогут вам понять нашу ситуацию.

Это представляет нашу основную сущность (Person), которая, помимо прочего, имеет отношения один-ко-многим с электронной почтой, а также с телефоном и отношения многие-к-одному с 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 на самом деле выбираются.

Это представляет страницу HTML...

<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 JOIN, как было предложено, но запрос выдает слишком много результатов: он должен получить только один экземпляр Person, представляющий Алису и содержащий два экземпляра Email, в поле personEmails, но я подозреваю, что он получает два разных экземпляры Person, каждый из которых имеет свой экземпляр Email.

Исходный запрос был следующим:

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

Еще раз спасибо.

AG

1 ответ

Решение

Я не знаю, как ты написал свой personFacade и получил сущность Person.

Но я думаю, что вы использовали запрос.

Если вы используете JPQL, попробуйте получить соединение.

Другие вопросы по тегам