Подтвердить что ты не робот

Как ленивая сборка при использовании spring -data-jpa, с гибернацией, из консольного приложения

У меня есть небольшое консольное приложение, и я использую spring -data-jpa с спящим режимом. Я действительно не могу понять, как ленить инициализировать коллекции при использовании spring -data-jpa с его репозиториями в автономном консольном приложении. Вот мой код:

@Entity
public class User {
...
    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="USER_ORDER_ID")
    private Set<Order> orders = new HashSet<Order>();
...
}

Репозиторий:

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;
}

мой основной метод:

...
user = userRepository.findByFirstNameIgnoreCase("john").get(0);
orders = user.getOrders();
for (Order order : orders) {
  LOGGER.info("getting orders: " + order.getId());
}    

цикл foreach получает исключение:

EVERE: не удалось лениво инициализировать коллекцию роли: com.aki.util.User.orders, сеанс или сеанс закрыты org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию роли:

Обратите внимание, что у меня нет этой проблемы при запуске этого из webapp с каким-то OpenSessionInViewFilter.

4b9b3361

Ответ 1

Одно из решений может заключаться в том, чтобы сделать User.orders желаемую подборку с помощью

@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Order> orders = new HashSet<Order>();

По умолчанию ассоциации объектов загружаются лениво. Это означает, что orders Set - фактически просто прокси-объект, который не будет инициализирован до тех пор, пока вы не вызовете на нем метод. Это хорошо, потому что связанные объекты Order не будут загружаться, если они не нужны. Однако это может вызвать проблемы, если вы попытаетесь получить доступ к неинициализированной коллекции за пределами выполняемой транзакции.

Если вы знаете, что в большинстве случаев вам потребуются Пользовательские заказы, имеет смысл сделать так, чтобы ассоциация с нетерпением ждала. В противном случае вам придется убедиться, что сбор инициализируется/загружается внутри транзакции. Вы упомянули OpenSessionInViewFilter, убедитесь, что транзакция остается открытой во время обработки запроса, поэтому у вас нет этой проблемы в веб-приложении yout.

В случае, если вы должны его лениво загружать, попробуйте использовать Spring TransactionTemplate, чтобы обернуть код в ваш основной метод:

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
    ...
    }
});

Ответ 2

Однако я нашел способ. Этот метод находится внутри моей реализации службы:

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

Примечание: это как @zagyi, добавленный в один из его комментариев, но также обратите внимание на инструкцию: Hibernate.initialize(user.getOrders()); без этого коллекция все равно не будет инициализирована, и вы получите сообщение об ошибке.

Ответ 3

Это сработало для меня:

@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();
    }
}