2012-12-26 88 views
1

我遇到了我的SEAM(2.2.2)應用程序中的惰性初始化異常問題,我正在使用文檔中描述的SEAM受管持久性上下文(與JPA)關於bean屬性的SEAM JSF惰性初始化異常

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 

起初我想,也許談話已經超時,但是這是從登錄的用戶,而不是拋出一個謊言

所以現在我想處理這可能是因爲用戶實體是從會話範圍注入的,而動作bean是對話範圍的,那麼該對象以某種方式脫離實體管理器?

不幸的是,沒有拋出異常每一次,所以我不能輕易地複製它(該應用程序是活的,所以我過到什麼時候得到錯誤)

我知道我可以通過設置用戶屬性解決這個問題急切地加載,但我想這個第一的底部,不希望加載所有實體前面

更多關於我的設置細節:

的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 
} 

回答

0

,如果你正從行動豆你的用戶實體嘗試在你的行動豆

用戶的用戶= entityManger.find(用戶。類,User.getId());

,因爲它看起來是您的評論後,分離

編輯這應該將其加載到擴展持久化上下文。

你肯定不會在你的getter方法中做到這一點,只需要在你對bean的訪問之前的任何方法中執行一次,它就會被傳遞給你的擴展PC,我會說你的行爲的@Create方法豆。關於你的最後一個問題:它是否被加載到Seam管理的持久化上下文中,這是被綁定的?

另外,您應該使用'@In EntityManager entityManager'注入實體管理器,因爲這是您的application.xml中的託管持久性上下文的配置。如果你的實體在這個對話中被加載到EPC中,那就足夠了。

+0

但是,當我通過JSF(el)訪問用戶實體時,我必須將.find()方法添加到Getter中,這意味着每次在頁面中引用該實體時都會重新加載該實體!我希望找出爲什麼實體首先被分離出來 – DaveB

+0

感謝您的更新,我會嘗試添加到@Create方法,正如您所建議的,我已經在我的GenericDAO抽象類中使用'@In EntityManager em' (見原文),還是你建議它需要注入到動作bean中? – DaveB

+0

你的配置是'name =「entityManager」'或name =「em」?是一致的,實體經理可以注入你需要的地方。我建議在'@Create'標記的方法中,只調用一次,您將您的用戶而不是entityManager引入您的擴展持久性上下文中進行此對話。你可以通過'user = entityManger.find(User.class,user.getId())來完成。這是延遲加載問題的一個對象,不是延伸到運行對話的擴展持久化上下文,而該對象是用戶。 – mariubog