关于bean属性的SEAM JSF Lazy Init异常

时间:2012-12-26 12:24:23

标签: java jsf richfaces seam seam-conversation

我在SEAM(2.2.2)应用程序中遇到了Lazy初始化异常的问题,我使用的是SEAM托管持久化上下文(使用JPA),在此处的文档中有描述

SEAM Docs Ref。 9.3.1 SEAM Managed Persistance Context with JPA

在我的GenericDAO类中使用@In注入实体管理器

情境:

我有一个会话范围的bean,它注入了当前登录的用户实体(会话作用域),当我试图通过页面中的JSF(el)懒洋洋地加载一些额外的用户属性时,LIE似乎被抛出。

堆栈跟踪错误:

2012-12-24 15:30:34,661 SEVERE [facelets.viewhandler] (http-0.0.0.0-8080-3) Error Rendering View[/user/settings.xhtml]: javax.el.ELException: /user/settings.xhtml: org.hibernate.LazyInitializationException: could not initialize proxy - no Session

at com.webapp.entities.Client_$$_javassist_29.getLogoUrl

起初我觉得对话可能已超时,但这是通过记录用户来处理,而不是扔掉LIE

所以现在我认为可能是因为用户实体是从会话范围注入的,而动作bean是对话作用域,对象是以某种方式与实体管理器分离的?

不幸的是,每次都不会抛出异常,所以我不能轻易地重现它(应用程序是活的,所以我会在以后的时候得到错误)

我知道我可以通过将用户属性设置为EAGERLY来解决这个问题,但我想先了解这个问题并且不想在前面加载所有实体

有关我的设置的更多详细信息:

的components.xml:

<persistence:managed-persistence-context name="entityManager"
    auto-create="true"
    persistence-unit-jndi-name="java:/EntityManagerFactories/appData">  
</persistence:managed-persistence-context>

的persistence.xml

<persistence-unit name="AppDatabase">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/appDatasource</jta-data-source>
    <properties>
        <property name="hibernate.connection.datasource" value="java:/appDatasource"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="jboss.entity.manager.factory.jndi.name" value="java:/EntityManagerFactories/appData"/>
        <property name="hibernate.cache.use_second_level_cache" value="false"/>
        <property name="hibernate.show_sql" value="false"/> 
    </properties>
</persistence-unit>

GenericDAO

public abstract class GenericDAOBean<T>
    implements GenericDAO<T>, Serializable{

private static final long serialVersionUID = 1L;

private Class<T> entityBeanType;

@In private EntityManager em;

@SuppressWarnings("unchecked")
public GenericDAOBean() {
    this.entityBeanType = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
}

/**
 * Set the entity manager to use
 * 
 * @param em
 */
public void setEntityManager(EntityManager em) {
    this.em = em;
}

/**
 * Get the current seam entity manager
 * 
 * @return
 */
 protected EntityManager getEntityManager() {
 //Seam entity manager set this way as of version 2.2.0 
 //can't handle abstract classes and @In doesn't inject
 //into this as a parent class
 EntityManager entityManager = (EntityManager)Component.getInstance("entityManager");
 if (entityManager == null)
     throw new IllegalStateException("Seam EntityManager has not been set on "
     +getEntityBeanType().getClass().getName()+"DAO before usage!");
     return entityManager;
 }

//Further Generic method follow here which are removed for brevity
}

1 个答案:

答案 0 :(得分:0)

如果从动作bean获取User实体,请尝试使用动作bean

User user = entityManger.find(User.class,User.getId());

这应该将它加载到扩展的持久性上下文中,因为它看起来像是分离的

您的评论后

修改

你当然不会在你的getter方法中这样做,只需在访问bean之前的任何方法中执行一次,它将被释放到你的扩展PC,我会说你在你的action bean的@Create方法中做到这一点。关于你的上一个问题:它是否曾被加载到Seam管理的持久化上下文中,这是对话绑定的?

此外,您应该使用'@In EntityManager entityManager'注入您的实体管理器,因为这是您在application.xml中配置托管持久性上下文。如果您的实体在此对话中被加载到EPC中,那就足够了。