JPA Criteria Lazy Container and session closed!

Hi everyone,
I’m using JPA Criteria Lazy Container along with spring OpenEntityManagerInView, I try to load a User entity in a table, User entity refers to Group, and Group.name is shown as a column in the table. randomly (and very frequently) I will get Session Closed exception. So is it a bug in my code (and I should keep looking) or is it unreasonable to use nested properties in this case (and they should be fetched eagerly)?

Nested properties should most likely be fetched eagerly, methinks. I don’t use Spring, so I can’t help much further.

I haven’t actually used this add-on, but I have used OSIV successfully with Vaadin.

You can check out my
ExpressUI
sample app, which uses OpenSessionInViewFilter in the
web.xml
.

The best approach is to keep your entity annotations lazy but add eager fetch joins as necessary to your queries to avoid the N+1 select problem.

Perhaps, your entity is being cached in the Vaadin application (HTTP session), although it had been previously attached to another JPA session from a previous HTTP request? It is hard to tell without knowing what your app is doing.

Juan

Most likely something like crossing requests, yes.

JPA Criteria Container includes a BeanTupleItemContainer which allows easy retrieval of joined entities. As suggested by Juan, I typically keep everything lazy, and use joins to fetch as needed. Say that a Person can perform 0…n Tasks. JPA can easily do an outer join, and the JPA Criteria Container will retrieve all the persons and tasks and pair them as they should (a BeanTuple is just that, a list of matching beans, in this case a person and a matching task). You can then use (say) person.name and task.duration to retrieve the attributes (i.e. you get nested entities for free).

Thanks guys that was very helpful, I’ll eager fetch the required data.

I tried fetching the group property, I prefer it over using tuples because I already wrote lots of code that depends on having one entity returned by the container, but I got the following exception

 org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias0,role=null,tableName=groups,tableAlias=applicatio1_,origin=users user0_,columns={user0_.group_id ,className=com.colureware.billing.domain.ApplicationGroup}}]
 [select count(distinct User) from com.colureware.billing.domain.User as User left join fetch User.group as generatedAlias0 where 1=1]

I used the fetch as follows:

Root<User> userRoot = criteriaQuery.from(User.class);
		userRoot.fetch("group", JoinType.LEFT);
		criteriaQuery.multiselect(userRoot);

This happens because you can’t have a fetch if you hadn’t selected the owner relation (select u from User will work but select count(User) … won’t because a User is not returned), I traced that BeanTupleQueryDefinition.getCountQuery and BeanTupleQueryDefinition.refresh, but I have no idea how to remove the fetch or clone the original Path.

Use a BeanTupleContainer and a BeanTupleQueryDefinition: these are the classes that know how to deal with joins and count the number of rows properly when dealing with a join. JPA is a little bit strange in these areas.

These two classes are very much the same as CriteriaContainer (which is in fact a special case).

        Root<CodeLocal> codeLocalEntity = cq.from(CodeLocal.class);
        Join<CodeLocal, Dico> pclocdEntity = codeLocalEntity.join(CodeLocal_.dico, JoinType.LEFT);
        
        cq.multiselect(
                codeLocalEntity.alias(CodeLocal.class.getSimpleName()),
                pclocdEntity.alias(Dico.class.getSimpleName()));

The only difference is that because there are potentially several items returned from a tuple, you need to qualify the properties (in this example I would refer to the properties as CodeLocal.id and Dico.id ).