'Fundamentals.How can you use Lazy fetching in Spring+Hibernate+=Vaadin after the session closes
There is the Customer entity which has a one to many relationship to entity Address,so there is a List<Address> getAddress
in Customer.Entity Address has three columns,Street,City and Country.Fetch type between Customer and Address is Lazy.
Given a Jparepository for Customer, when doing findById(5) fetches the Customer entity for id=5.You display that in a Vaadin grid and then persumably the session closes (or does the session close immediately after the Service calls the Repository and ggets the rows?).
Then when on the grid you try to expand Cutomer in order to see his addresses isn't there a customer.getAddress() call going to happen behind the scenes?Since it is Lazy it will fire a new SQL query but with no session open it will cause a LazyInitializationException.
This is the very case I encountered even whne just binding Customer to the grid without making an attempt to call the Address.That has been solved by changing to Fetch type Eager.But if there are more relationships with Customer,like a customer having multiple Offices, loading entitires up front with Eager might prove detrimental.
BUT Isn't that a fundamental problem not just pertaining to Vaadin but to all Spring applications using hibernate? I mean are all the apps written with that stack all using relationships EAGER? In the scenario above I see not how you can go Lazy fetching. Should a new session be opened when customer.getAddress() is called?
I'm aware of the FETCH JOIN but that would mean write a custom SQL query to fill a DTO.if you don't want to use a DTO and use the Entities themselves to traverse by using the relationships like customer.getAddress.get(0).getStreet
, what can you do?
Solution 1:[1]
This is a common problem to spring MVC applications (as you and davidcyp comment). There are two important aspects to take into account for the solution:
By one side data design and usage, and the database accesses that are required according to both of them. Whenever a database access is to be made (including accesses that are consequence of lazy accesses), you should have an open hibernate session, and additionally, all entities taking part in the access must be attached to that session. So, in your case, when the SQL code for customer.getAddress is sent to the database, you should have a session, and the customer should be attached to that session.
By other side, there are different ways to configure session management. You can have a session attached for a whole web request, or you can have "smaller" sessions, attached to inner services. You can find an exposition for vaadin + hibernate here: https://vaadin.com/docs/v7/framework/articles/UsingHibernateWithVaadin
Taking all this into account, for your situation I would choose probably to use the session-per-request pattern (as commented in the link above), but you perhaps have other arguments according to other application conditions.
Then, once you have decided the adequate session management, there seem to be three main options in order to solve the problem:
- Use EAGER fetching.
- Programmatically retrieve the data previously to access it. So, execute a customer.getAddress at the moment when the customer is retrieved. This is equivalent to EAGER fetching but it has the advantage that you can decide in which situations you want to pre-fetch the data (for example you might have two different views and only need that pre-fetched data in one of them). As a negative side, it might seem a bit uglier.
- Keep the relation as LAZY, retrieving data when you need it, but then you must be sure that you have an hibernate session there, and that the customer entity is attached to it (you can use merge for that if the customer entity was retrieved with another session, an example also in the previous link).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Jordi Alvarez |