【发布时间】:2014-05-06 15:25:05
【问题描述】:
我目前正在尝试学习 JSF 和 JPA。我知道我使用的模式根本不被推荐,但我想了解发生了什么,因为我认为它会在未来帮助我。我刚刚从各种来源拼凑出一个原型。
我在下面描述的设置中遇到的问题是,显然 JPA 实体一直在分离,这反过来又是因为支持 bean 被一遍又一遍地序列化。事实上,如果我从实体类中删除Serializable接口,我得到Exiting serializeView - Could not serialize state: com.sk.Message
由于实体是分离的,所以当我调用EntityManager.commit() 时,不会向数据库提交任何内容。如果我手动将所有实体(下面onCellEdit() 中注释掉的行)与EntityManager.merge() 合并,则修改后的实体将提交到数据库。
我已经从其他 SO 帖子中发现我可以通过添加来解决这个问题
<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>false</param-value>
</context-param>
到我的 persistence.xml。但也有人指出,这只是一种解决方法,而不是解决方案。
所以我的问题是:
- 是否有意/预期
@ViewScopedJSF 支持 bean 会一遍又一遍地序列化(同时始终保持在同一个视图上),这使得在其中使用 JPA 实体变得困难? - 使用
SERIALIZE_STATE_IN_SESSION参数是否安全/合理? - 正如我多次推荐的那样,我是否应该完全忘记 JSF 托管 bean 并直接使用 CDI(例如
@ConversationScope来实现类似的目标)?
我将 TomEE(MyFaces、OpenJPA)与 PrimeFaces 结合使用。支持 bean 包含以下代码:
@ViewScoped
@ManagedBean
public class MessageBean implements Serializable
{
private List<Message> messages;
public List<Message> getMessages()
{
return messages;
}
public void setMessages( List<Message> messages )
{
this.messages = messages;
}
@PostConstruct
public void init()
{
messages = PersistenceManager.getInstance().queryMessages();
}
public void onCellEdit( CellEditEvent event )
{
// PersistenceManager.getInstance().mergeMessages( messages );
PersistenceManager.getInstance().commitTransaction();
}
[...]
Message 是一个 JPA 实体,如下所示:
@Entity
@Table( name = "message" )
@NamedQuery( name = "Message.findAll", query = "SELECT a FROM Message a" )
public class Message implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column( unique = true, nullable = false )
private Integer dbid;
@Column( nullable = false, length = 14 )
private String no;
[...]
}
使用 PrimeFaces 数据表从 JSF 页面引用支持 bean:
<h:form id="navForm">
<p:dataTable
id="messages"
value="#{messageBean.messages}"
var="message"
editable="true"
editMode="cell">
<f:facet name="header">MESSAGE</f:facet>
<p:ajax
event="cellEdit"
listener="#{messageBean.onCellEdit}"
update=":navForm:messages" />
<p:column>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{message.no}" />
</f:facet>
<f:facet name="input">
<p:inputText
id="modelInput"
value="#{message.no}" />
</f:facet>
</p:cellEditor>
<f:facet name="header">Message number</f:facet>
</p:column>
[...]
我知道我在这里可能违反了许多最佳实践,但对于原型设计,我创建了一个单例 POJO,PersistenceManager,它处理 JPA 接口(以及可能的其他数据源)。我使用应用程序管理的本地资源EntityManager。摘录如下:
public class PersistenceManager
{
private static PersistenceManager INSTANCE;
private EntityManagerFactory emf;
private EntityManager em;
private EntityTransaction entr;
private PersistenceManager( PersistenceType persistenceType )
{
emf = Persistence.createEntityManagerFactory( "MessagePU" );
em = emf.createEntityManager();
}
public List<Message> queryMessages()
{
TypedQuery<Message> query = em.createNamedQuery( "Message.findAll", Message.class );
return query.getResultList();
}
public void commitTransaction()
{
if ( entr != null && entr.isActive() )
{
entr.commit();
}
}
[...]
【问题讨论】:
标签: jsf jpa serialization view-scope apache-tomee