0

I found many times on stackoverflow this issue, but nothing from them gives me clear answer. For simplicity, there are only two tables film and language bound many to one relation. Everything done according Netbeans Hibernate DVD Store tutorial. Now, how to display in first page (index.xhtml) language. It looks like very straightforward. Simply add:

                  <h:column>
                    <f:facet name="header">
                        <h:outputText value="Language"/>
                    </f:facet>
                    <h:outputText value="#{item.languageByLanguageId.langName}"/>
                 </h:column>

(Comumn in table language name was renamed on langName) But it issues still the same LazyInitializationException. I tried to obtain languageId and in this case I was successful. It means #{item.languageByLanguageId.langName} gives exception but #{item.languageByLanguageId.languageId} not. It is strange. So what happen, when I use explicit fetch according languageId if I can obtain its.

So I added in FilmController.java method for obtaining language:

  public String getLanguageById(Integer langId) {
    String language = helper.getLangById(langId);
    return language;
  }

And in FilmHelper.java (final version):

  public Film getFilmById(int filmId) {

Film film = null;

try {
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    org.hibernate.Transaction tx = session.beginTransaction();
    Query q = session.createQuery("select count(film.filmId) from Film as film where film.filmId = :filmId");
    q.setParameter("filmId", filmId);
    Number count = (Number) q.uniqueResult();
    if (count.intValue() > 0)
      film = (Film) session.load(Film.class, filmId);
    tx.commit();
} catch (Exception e) {
    e.printStackTrace();
}

return film;

}

And yes, it works, I can obtain language name to modify index.xhtml:

<h:outputText value="{filmController.getLanguageById(item.languageByLanguageId.languageId)}"/>

Than I tried to modify FilmActor.hbm.xml to add lazy="false" and use origin simple solution in index.xhtml ("#{item.languageByLanguageId.langName}"):

<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" lazy="false" fetch="select">
        <column name="original_language_id" />
    </many-to-one>

Again it works properly. Even if I set lazy="proxy" or lazy="no proxy". But still I don't understand, how to use this default attribute lazy="true". If I try to keep whole document in one session (don't do commit, which causes end of session), there is another Exception issue. It looks like, that lazy="true" doesn't meet in any time proper result.

2 Answers 2

1

With setting lazy=true attribute you are allowing hibernate to delay association retrieving. So when you disable lazy=false then hibernate will immediate do its fetching method, just after parent instance is retrieved. Yours problem will be solved if you set fetch="join".

Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT, using an OUTER JOIN.

Your example;

<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" fetch="join">
        <column name="original_language_id" />
</many-to-one>

You can look at fetch and lazy as how and when, respectively. In your example lazy=false solved your problem but still two queries where done because your fetch method was select. Hibernate Fetching Strategies

UPDATE

Once when object is lazy initialized, you have only properties of your entity and lazy initialized association (only id you have). Then that object is passed for further(transaction is committed already) use and you want to use one of lazy initialized association(in your case Language) and got exception. This is happening because you are accessing lazy object and your transaction is already commited, so hibernate wants to execute your second query without success (fetch="select"). This can be fixed by moving the code that reads association to just before the transaction is committed.

When your object is detached and your current session is closed then you must do

Hibernate.initialize(entity)

to assign your detached entity to another session.

Sign up to request clarification or add additional context in comments.

Comments

0

Thank you for explanation. I tested your advice. It works and I suppose, that join should be quicker than two distinct selects (it depends on indexes, optimizer, etc.), but still when I try combination lazy="true" and fetch="join" it again fails:

<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" lazy="true" fetch="join">
  <column name="original_language_id" />
</many-to-one>

Even if exception is different, still no succes:

java.lang.ExceptionInInitializerError
    at controller.HibernateUtil.<clinit>(HibernateUtil.java:30)

However, there are clearly explained three ways, how to avoid problems with default or explicit lazy="true".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.