tutorial - tipos de consultas utilizadas por hibernate
cómo realizar una carga perezosa cuando se utiliza spring-data-jpa, con hibernación, desde una aplicación de consola (3)
Esto funcionó para mí:
@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();
}
}
Tengo una aplicación de consola pequeña y estoy usando spring-data-jpa con hibernate. Realmente no puedo encontrar la forma de inicializar las colecciones de forma perezosa al utilizar spring-data-jpa con sus repositorios, en una aplicación de consola independiente. Aquí está algo de mi código:
@Entity
public class User {
...
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="USER_ORDER_ID")
private Set<Order> orders = new HashSet<Order>();
...
}
repositorio:
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
public ArrayList<User> findByFirstNameIgnoreCase(String firstName);
}
servicio implícito:
@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;
}
mi principal método:
...
user = userRepository.findByFirstNameIgnoreCase("john").get(0);
orders = user.getOrders();
for (Order order : orders) {
LOGGER.info("getting orders: " + order.getId());
}
el bucle foreach obtiene una excepción:
EVERE: no se pudo inicializar perezosamente una colección de roles: com.aki.util.User.orders, no se cerró ninguna sesión o sesión org.hibernate.LazyInitializationException: no se pudo inicializar perezosamente una colección de roles:
Tenga en cuenta que no tengo este problema al ejecutar esto desde una aplicación web con algún tipo de OpenSessionInViewFilter.
Sin embargo, encontré un camino. Este método está dentro de mi implementación de servicio:
public Set<Order> fetchUserOrders(Long userId) {
User user = userRepository.findOne(userId);
Hibernate.initialize(user.getOrders());
Set<Order> orders = user.getOrders();
return orders;
}
Nota: esto es como @zagyi sugirió en uno de sus comentarios, pero también preste atención a la declaración: Hibernate.initialize(user.getOrders());
sin esto, la colección aún no se inicializará y obtendrá un error.
Una solución puede ser hacer de User.orders
una colección ansiosamente User.orders
por
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Order> orders = new HashSet<Order>();
Las asociaciones de entidades se cargan perezosamente por defecto. Esto significa que el conjunto de orders
es en realidad solo un objeto proxy que no se inicializará hasta que invoque un método en él. Esto es bueno, porque los objetos de Order
asociados no se cargarán a menos que sean necesarios. Sin embargo, esto puede causar problemas, si intenta acceder a la colección sin inicializar fuera de una transacción en ejecución.
Si sabe que, en la mayoría de los casos, necesitará las Órdenes del Usuario, tiene sentido hacer la asociación con entusiasmo. De lo contrario, deberá asegurarse de que la recopilación se inicialice / cargue dentro de una transacción. El OpenSessionInViewFilter
que mencionó se asegura de que la transacción permanezca abierta durante el procesamiento de la solicitud, es por eso que no tiene este problema en su aplicación web.
En caso de que deba mantenerlo cargado perezosamente, intente utilizar la plantilla de TransactionTemplate
de Spring para ajustar el código en su método principal:
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
}
});