Лечение:
1)меняем аннотацию на @XXXToXXX(fetch =FetchType.EAGER) - самый простой способ но вызывает осложнения типа долгой загрузки объекта
2)вычитав объект впервые тут же инициализируем поле с FetchType.LAZY -
делаем это так - hibernateTemplate.initialize(entity) - самый бестолковый способ
3)даём новой сессии права на работу с объектом -
if (!hibernateTemplate.contains(track)) {
hibernateTemplate.lock(track, LockMode.READ);;- самый клёвый способ НО!
you only use lock() if you are sure that the object has not been modified - иначе
org.springframework.dao.InvalidDataAccessApiUsageException: cannot lock an unsaved transient instance:
4) делать всё в одной сессии
5)прикрепляем к новой сессии через
if (!hibernateTemplate.contains(track)) {
hibernateTemplate.merge(track);}
6)если таки точно собрались загружать поля то можно сделать hql запрос типа:List<Customer> list = hibernateTemplate.find(
"select distinct с from Customer с " +
"left join fetch c.orders where c=?", customer);
в sql
select
distinct
c
from
Customer c
left
join
fetch
c.orders
http://bwinterberg.blogspot.com/2009/08/how-to-eagerly-fetch-associations-with.html
7)Есть спец фильтры для загрузки нужных частей сущностей см. тут
http://bwinterberg.blogspot.com/2009/09/hibernate-preload-pattern.html
8)держать сессию открытой(паттерн типа '...а после нас хоть потоп') http://alekseiko.blogspot.com/2010/02/hibernate-lazyinitializationexception.html
9)загрузить по id, выставить необходимые поля, сохранить
10)Написать свою аннотацию, которая будет проверять необходимость переподключения коллекции к новой сессии: http://9mmedia.com/blog/?p=272
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html
ОтветитьУдалитьЭто просто блеск! Сразу все и в одном месте. Спасибо!
ОтветитьУдалитьНужен совет.
ОтветитьУдалитьЕсть два класса user и role.
User.id <-many-to-many-> Role.id
И есть следующий class
Factory
-- static role = null (Это для синглетона)
-- static user = null (Это для синглетона)
-- session = null (Сессия)
--> openSession() (открываю сессию openSession())
--> closeSession() (закрываю сессию)
--> getUserDAO() (singleton)
--> getRoleDAO() (singleton)
на уровне сервиса работаю так.
factory.openSession();
User user = factory.getUserDAO().getUserByLogin("Admin");
roles = user.getRoles(); // вот тут lazy exception
factory.closeSession();
в getUserByLogin:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
user = (User) session.get(User.class, login);
session.getTransaction().commit();
второй день уже пляшу вокруг этого LazyException.
Вроде и сессия открыта. И в других местах не закрывается. Использовать агрессивную загрузку не хочу т.к. many-to-many.
Попробуй делать в одной транзакции получение юзера и его полей, см как юзать TransactionCallbackWithoutResult, TransactionCallback
ОтветитьУдалитьДолго бился со своим убеждением в MVC необходимо строго разделять все части.
ОтветитьУдалитьПрочитав OpenSessionInView понял: есть инструменты которые возможно использовать в строгой MVC, а есть такие, которые пронизывают проект насквозь.
В общем пришел к выводу: реализую п. 4. с оговрокой на транзакцию. По крайней мере это не противоречит моим убеждениям.