2013-02-25 111 views
2

我有一個JSF管理的會話範圍豆包含跟蹤的實體,例如,通過認證的用戶:無法刷新JPA 2實體注入到JSF 2託管Bean

@ManagedBean 
@SessionScoped 
public class LoginController implements Serializable { 
    User user; 

    public User getUser() { 
    return this.user; 
    } 

    public void setUser(User user) { 
    this.user = user; 
    } 
    /* ... */ 
} 

在另一個bean我有注入用戶使用它來檢索角色列表中的關聯有了它,像這樣:

@ManagedBean 
@ViewScoped 
public class AnotherController implements Serializable { 

    List<Role> roles;  

    @ManagedProperty(value="#{loginController.user}") 
    User user; 

    public someMethod() { 
    /* Some stuff that insert other roles into database, referring the user as owner */ 
    roles = user.getRolesList(); 
    } 
} 

如果我更新使用someMethod AJAX頁面時,roles名單仍然沒有重新加載。 如果我插入em.refresh(user)user.getRolesList之前,我得到這個錯誤:

Can not refresh not managed object: model.User[ id=1 ]. 

誰能幫助我理解?爲什麼會話範圍的實體如果注入另一個bean,就不會被管理?我怎樣才能解決這個問題? 謝謝。

回答

7

爲了讓物品能夠刷新,需要進行管理,但您已經知道了。 爲它是mananged,它必須是要麼

  • 重新獲取
  • 合併,然後刷新
  • 保持與擴展的持久化上下文

前兩個選項需要一個事務管理。

由於@ManagedBean@ViewScoped均暗示任何類型的事務管理,因此這些bean中的實體將始終分離,因此您遇到的行爲是預期的JPA行爲。

對於前兩個選項,您可以將請求傳遞給後端中啓用事務的EJB,該EJB將合併並更新實體或返回一個新提取的實體。如果您未使用Java EE應用程序服務器,則可以使用UserTransaction

對於第三個選項,您可以使用擴展的持久化上下文,該擴展持久化上下文在每次事務之後都不會關閉,因此實體保持跨事務邊界進行管理。

編輯修復此問題的最簡單方法,使用UserTransaction並假定依賴注入。所有的

@Inject 
UserTransaction tx; 

    //merging and refreshing 
    tx.begin(); 
    User managedUser = em.merge(user); 
    em.refresh(managedUser); 
    tx.commit(); 
    user = managedUser; 

    //refetching 
    tx.begin(); 
    user = em.find(User.class, user.getId); 
    tx.commit(); 
+0

+1有一個很好的解釋。我會親自去使用帶有後端'@EJB'服務的分離對象來完成合並作業。或者,如果OP不想處理EJB,則會使用ORM,例如Hibernate,並以編程方式處理事務。 – skuntsel 2013-02-25 10:13:14

+0

對不起,但我是新來的Java世界,現在我使用jsf有點'開箱',所以我不是很確定理解了解釋,我該如何解決練習問題? – 2013-02-25 10:43:30

+0

我認爲以這種方式解決了我的問題:'user = em.find(user.getClass(),user.getId());' – 2013-02-25 11:20:17

1

首先,你要分開您的問題,這基本上意味着您的支持bean 不應該執行任何業務邏輯直接(這是由您的評論/* Some stuff that insert other roles into database, referring the user as owner */暗示)。相反,您可以使用@EJB註釋在您的託管bean中注入UserService類,並通過commandComponents的操作調用它的方法。

接下來,當你從數據庫中獲取你的實體和從持久化上下文分離它(讀:持久化上下文在交易結束時關閉),這意味着實體不是由您的持久性服務了管理和對實體的更改不會反映在數據庫中。如果你想這樣做,你需要撥打EntityManager.merge(),使實體持久。您需要這樣做,以便在LoginController.user對象中的數量爲的數據持續存在中。

所以,Kostja說什麼是當你想獲得你的用戶對象和數據庫中的行之間的最新對應關係時,你應該使你的對象由你的EntityManager管理,按照他的方式之一建議。

+0

+1正確.. :) – kostja 2013-02-25 11:37:57

+1

那麼,只是想'@注入'一些更多的解釋給你的答案。 – skuntsel 2013-02-25 11:42:32