Posted on: 2015-01-23, Last modified: 2015-07-31, View: 3300
页面使用<pf:selectCheckboxMenu>控件多选值时,新建对象没有问题,编辑时一直报LazyInitializationException异常:
信息: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
通过一步步调试跟踪源代码,发现问题:
1、当有ajax提交时就抛出这个异常,排除后台自编代码的问题;
2、跟踪JSF代码发现是validatior的时候出错
3、进一步调试代码发现是jsf的问题,其中有个MenuRender类会判断数据源的类型,如果是Collection类型的话,要调用其Add方法,进一步调用write()方法,会检查当前session然后取数据源的值,这个时候因为我们用的ViewBean,session早已失效,就会抛出这个异常。具体方法可以查看com.sun.faces.renderkit.html_basic.MenuRenderer类的convertSelectManyValuesForModel()方法。
if (modelType.isArray()) { return convertSelectManyValues(context, uiSelectMany, modelType, newValues); } else if (Collection.class.isAssignableFrom(modelType)) { ... targetCollection.add(v); ... }
if ( session == null ) { if ( allowLoadOutsideTransaction ) { session = openTemporarySessionForLoading(); isTempSession = true; } else { throwLazyInitializationException( "could not initialize proxy - no Session" ); } }
解决方案:
1、刚开始想着提交新值时不做validation可以解决问题,就试着加上了immediate = true,结果不好使。调试的时候发现不管immediate的值是true还是false, validate()方法竟然都在执行,UiiNput类里processDecodes()方法在immediate = true时候调用validate,processValidators()方法里当immediate = false时调用validate(),没有办法只能放弃这个打算;
2、查看PrimeFaces官方的demo,发现他在使用<pf:selectCheckboxMenu>控件时选中值并不是用的Colection结构,而是用的array。再回到convertSelectManyValuesForModel()方法发现原来在选中值的类型是array时不会有Collection类型add方法的问题,也就是不会牵扯到Session的失效与否,接着把选中值改成Array果然解决问题。
感觉PrimeFaces肯定也是发现了这个问题,没有好的解决方案只能使用Array来记录选中值绕过这个问题,使用的时候只能跟着一起走,问题解决不进一步深究,希望以后的Primefaces版本中能够解决这个问题。