how to lazy load collection when using spring-data-jpa, with hibernate, from an console application

后端 未结 3 1420
生来不讨喜
生来不讨喜 2020-12-29 03:20

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

相关标签:
3条回答
  • 2020-12-29 03:46

    However, I found a way. This method is inside my service implementation:

    public Set<Order> fetchUserOrders(Long userId) {
        User user = userRepository.findOne(userId);
        Hibernate.initialize(user.getOrders());
        Set<Order> orders = user.getOrders();
        return orders;
    }
    

    Note: this is as @zagyi sugested in one of his comments, but also pay attention to the statement: Hibernate.initialize(user.getOrders()); without this the collection still wouldn't be initialized and you will get an error.

    0 讨论(0)
  • 2020-12-29 03:46

    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) {
        ...
        }
    });
    
    0 讨论(0)
  • 2020-12-29 03:55

    This worked for me:

    @Component
    public class Test {
    
        @Inject 
        OrderDAO orderDAO;
    
        @PersistenceUnit
        private EntityManagerFactory emf;
    
        @PostConstruct
        public void test(){
            EntityManager em= emf.createEntityManager();
            for (Order o:orderDAO.findAll()){
                o=em.find(o.getClass(),o.getId());
                System.out.println(o.getLazyField());
            }
            em.close();
        }
    }
    
    0 讨论(0)
提交回复
热议问题