Would like to hear experts on best practice of editing JPA entities from JSF UI.
So, a couple of words about the problem.
Imagine I have the persisted object
For Hibernate >= 4.1.6 read this https://stackoverflow.com/a/11913404/3252285
Using the OpenSessionInView Filter (Design pattern) is very usefull, but in my opinion it dosn't solve the problem completely, here's why :
If we have an Entity stored in Session or handled by a Session Bean or retrieved from the cache, and one of its collections has not been initialized during the same loading request, then we could get the Exception at any time we call it later, even if we use the OSIV desing pattern.
Lets detail the problem:
Listener or Handler) to reatach the proxy in case his session is closed or he's detached from its own session.Why hibernate dosn't offer that ? : because its not easy to identify to which Session, the Proxy should be reatached, but in many cases we could.
So how to reattach the proxy when the LazyInitializationException happens ?.
In my ERP, i modify thoses Classes : JavassistLazyInitializer and AbstractPersistentCollection, then i never care about this Exception any more (used since 3 years without any bug) :
class JavassistLazyInitializer{
@Override
public Object invoke(
final Object proxy,
final Method thisMethod,
final Method proceed,
final Object[] args) throws Throwable {
if ( this.constructed ) {
Object result;
try {
result = this.invoke( thisMethod, args, proxy );
}
catch ( Throwable t ) {
throw new Exception( t.getCause() );
}
if ( result == INVOKE_IMPLEMENTATION ) {
Object target = null;
try{
target = getImplementation();
}catch ( LazyInitializationException lze ) {
/* Catching the LazyInitException and reatach the proxy to the right Session */
EntityManager em = ContextConfig.getCurrent().getDAO(
BaseBean.getWcx(),
HibernateProxyHelper.getClassWithoutInitializingProxy(proxy)).
getEm();
((Session)em.getDelegate()).refresh(proxy);// attaching the proxy
}
try{
if (target==null)
target = getImplementation();
.....
}
....
}
and the
class AbstractPersistentCollection{
private T withTemporarySessionIfNeeded(LazyInitializationWork lazyInitializationWork) {
SessionImplementor originalSession = null;
boolean isTempSession = false;
boolean isJTA = false;
if ( session == null ) {
if ( allowLoadOutsideTransaction ) {
session = openTemporarySessionForLoading();
isTempSession = true;
}
else {
/* Let try to reatach the proxy to the right Session */
try{
session = ((SessionImplementor)ContextConfig.getCurrent().getDAO(
BaseBean.getWcx(), HibernateProxyHelper.getClassWithoutInitializingProxy(
owner)).getEm().getDelegate());
SessionFactoryImplementor impl = (SessionFactoryImplementor) ((SessionImpl)session).getSessionFactory();
((SessionImpl)session).getPersistenceContext().addUninitializedDetachedCollection(
impl.getCollectionPersister(role), this);
}catch(Exception e){
e.printStackTrace();
}
if (session==null)
throwLazyInitializationException( "could not initialize proxy - no Session" );
}
}
if (session==null)
throwLazyInitializationException( "could not initialize proxy - no Session" );
....
}
...
}
NB :