2011-08-20 69 views
2

我正在編寫一個JSF 2.0表單來編輯JPA @Entity對象。我有一個支持bean,它有一個EntityManager的get方法,它從EntityManager中獲取。到現在爲止還挺好。實體的JSF表單 - 熱門編輯?

問題是用戶正在編輯的實體對象是否被應用程序的其他部分訪問?換句話說,如果其他人調用該記錄,他們在通過EntityManager將記錄合併回數據庫之前是否會看到字段更改?或者他們獲得不同的實例。

這很重要的原因是用戶可以輸入各種不良數據。由後臺bean完成的驗證階段不會調用merge()所有的錯誤都被清除,但是之前呢?

如果這是一個常見的情況,我該如何避免這個問題?

回答

3

問題是由用戶編輯的實體對象是否被應用程序的其他部分訪問?換句話說,如果其他人調用該記錄,他們在通過EntityManager將記錄合併回數據庫之前是否會看到字段更改?或者他們獲得不同的實例。

JSF使用的實體實例將是一個分離的實體實例。它不屬於持久性上下文。每個客戶/用戶也將收到它自己的分離實體實例。

這很重要的原因是用戶可以輸入各種不良數據。由支持bean完成的驗證階段不會調用merge()所有的錯誤都被清除,但那麼在那之前呢?

當您調用EntityManager.merge將分離實體的內容與持久性上下文合併時,將發生任何無效數據的合併。如果您從未調用merge,則該實體的修改內容將永遠不會將其設置爲持久性上下文。

如果這是一個常見的情況,我該如何避免這個問題?

您可以通過在與持久化上下文合併之前驗證實體的狀態來避免這種情況。您可以在JSF和JPA中使用bean驗證,以防止出現這種情況,儘管您通常只在一層中執行此操作,以防止重複檢查。但是,如果您爲bean驗證約束指定了驗證組以區分表示和持久性約束,則應該在這兩個層中使用bean驗證。請記住,一旦bean的內容與持久化上下文成功合併,除了事務回滾或持久化上下文之外,您可以做的很多事情可以撤消此更改。

+0

感謝您的澄清。如果javadoc提到** getSingleResult()**返回一個分離的實體,那將會很好。我假設** getResultList()**也是如此。 – AlanObject

+0

當實體不再是持久化上下文的一部分時,就會發生實體分離。它通常會在EntityManager離開事務上下文時自動發生,即當事務提交或回滾時,或者當您調用'EntityManager.detach'時顯式地自動發生。 'Query.getSingleResult'或'Query.getResultList'將總是返回一個託管實體。當交易結束時,這個被管實體變成一個分離的實體。 –

+0

您將在[OpenEJB概念指南](http://openejb.apache.org/3.0/jpa-concepts.html)中以易於理解的方式找到這些概念。 –

2

添加到維尼特的正確答案:

你可能有一個附加的實體通過您的支持bean,如果你使用一個有狀態會話bean(EJB)與擴展持久化上下文返回,例如。

在這種情況下,但是你仍然不會冒險併發問題,因爲持久化上下文的每個實例返回連接實體(獨特之處:例如不與其他現有的持久化上下文共享)的唯一實例。

此外,JSF不會推變爲如果發生任何一種驗證錯誤的模型(在這種情況下,附JPA實體)。因此,只要您的驗證設置正確(bean驗證或常規JSF驗證),就不存在「污染」實體的風險。

此外,請注意,對於附加的情況,您不必調用merge(),因爲這將在上下文關閉時自動發生,因此請關閉有狀態bean。

也就是說,通常情況下是一個維尼特描述你在哪裏得到分離實體。