I have an small console application and I am using spring-data-jpa with hibernate. I really can not figure out how to lazy initialize collections when using spring-data-jpa with its repositories, in an standalone console application. Here is some of my code:
@Entity public class User { ... @OneToMany(cascade=CascadeType.ALL) @JoinColumn(name="USER_ORDER_ID") private Set<Order> orders = new HashSet<Order>(); ... }
repository:
public interface UserRepository extends PagingAndSortingRepository<User, Long> { public ArrayList<User> findByFirstNameIgnoreCase(String firstName); }
service impl:
@Service @Repository @Transactional public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; public ArrayList<User> findByFirstNameIgnoreCase(String firstName) { ArrayList<User> users = new ArrayList<User>(); users = userRepository.findByFirstNameIgnoreCase(firstName); return users; }
my main method:
... user = userRepository.findByFirstNameIgnoreCase("john").get(0); orders = user.getOrders(); for (Order order : orders) { LOGGER.info("getting orders: " + order.getId()); }
the foreach loop gets an exception:
EVERE: failed to lazily initialize a collection of role: com.aki.util.User.orders, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
Please note that I do not have this problem when running this from an webapp with some kind of OpenSessionInViewFilter.
To enable lazy loading explicitly you must use “fetch = FetchType. LAZY” on an association that you want to lazy load when you are using hibernate annotations. @OneToMany( mappedBy = "category", fetch = FetchType.
Hibernate now can "lazy-load" the children, which means that it does not actually load all the children when loading the parent. Instead, it loads them when requested to do so. You can either request this explicitly or, and this is far more common, hibernate will load them automatically when you try to access a child.
This is the type of code Spring Data JPA helps to avoid. Spring Data JPA is really a set of dependencies that makes it easier to work with a JPA provider. Hibernate is one of several JPA providers. This means you can use Spring Data JPA without using Hibernate (if you really wanted to).
By default, JPA uses the lazy fetch strategy in associations of type @ElementCollection. Thus, any access to the collection in a closed Persistence Context will result in an exception. This test throws an exception when we try to access the phone list because the Persistence Context is closed.
One solution can be to make User.orders
an eagerly fetched collection by
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER) private Set<Order> orders = new HashSet<Order>();
Entity associations are lazily loaded by default. This means that the orders
Set is actually just a proxy object that won't get initialized until you invoke a method on it. This is good, because the associated Order
objects won't get loaded unless they are needed. However, this can cause problems, if you try to access the uninitialized collection outside of a running transaction.
If you know that in most of the cases you will need the User's Orders, it makes sense to make the association eagerly fetched. Otherwise you will have to ensure that the collection gets initialized/loaded inside a transaction. The OpenSessionInViewFilter
you mentioned makes sure that the transaction stays open during the request processing, that is why you don't have this issue in yout webapp.
In case you must keep it lazily loaded, try using Spring's TransactionTemplate
to wrap the code in your main method:
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { ... } });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With