Zdravím,
OpenEntityManagerInViewInterceptor i OpenEntityManagerInViewFilter jsou
záležitosti čistě webové (interceptor implementuje
spring.WebRequestInterceptor, filter spring.OncePerRequestFilter),
jejich registrace nemá žádný vliv na to, jak se lazy loading chová v
testech - tam se ani jeden z uvedených typů nedostane ke slovu.
Klíčové pro pochopení lazy loading je doba životnosti tzv.
persistentního kontextu. JPA definuje dva rozsahy (viz JPA spec. část
Persistence Context Lifetime):
1) Transaction
2) Extended
přičemž Transaction je default. Pro funkční lazy loading platí, že se
nesmí zrušit persistentní kontext, ve kterém byla asociace
(reprezentovaná runtime nějakou proxy třídou, v příkladu asocociace
emails) načtena. V uvedeném příkladě zanikne persistentní kontext již
po dokončení metody dao.findById(result.getId()), takže následující
volání getEmails() vyhodí LazyInitException.
Váš problém vyřeší, pokud si převedete "business transakci 'Načtení
osoby a emailů'" do jedné metody označené @Transactional:
@Transactional
public List<Email> getEmails(Person person) {
dao.findById(person.getId());
return person.getEmails();
}
to bude fungovat, protože persistentní kontext je "roztažen" přes celou
transakci.
Poznámka: ani OpenEntityManagerInViewFilter vás nezbaví
LazyInitException "trvale", pouze pro asociace, ke kterým se přistupuje
v rámci jednoho request/response. Např. pro lazyloading spolu se
stránkováním pomocí query.setMaxResult() potřebujete "roztáhnout"
persistentní kontext na "větší" scope než je request, např. podle
http://www.hibernate.org/43.html.
Jiří Hradil píše v So 24. 01. 2009 v 11:39 +0100:
> OpenEntityManagerInViewInterceptor