我目前正在尝试学习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。但也有人指出,这只是一种解决方法而不是解决方案。
所以我的问题是:
@ViewScoped
JSF支持bean反复序列化(同时始终保持相同的视图),这使得在其中使用JPA实体变得困难?SERIALIZE_STATE_IN_SESSION
参数是否安全/合理? @ConversationScope
来实现类似的东西)?我在PrimeFaces中使用TomEE(MyFaces,OpenJPA)。辅助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 DataTable从
<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();
}
}
[...]
答案 0 :(得分:2)
在提交交易之前,您必须启动它(然后在交易结束时关闭它)。如果else
对象未激活和/或commitTransaction
,EntityTransaction
方法中的null
语句在哪里?
另外,我在代码中看不到任何 EJB 。 POJO 方法不是由容器管理,提供和托管的应用程序中的最佳选择。
对我来说,在 JSF 和 JavaEE 应用程序中实现持久层的最佳方法是会话外观模式,你可以在网上搜索它,有很多参考资料。
在你的情况下,这样的事情就可以了。
消息Facade,用于管理与Message实体相关的事务。
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class MessageFacade extends AbstractFacade<Message> {
@PersistenceContext(unitName = "MessagePU")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
public MessageFacade() {
super(Message.class);
}
public List<Message> queryMessages()
{
TypedQuery<Message> query = em.createNamedQuery( "Message.findAll", Message.class );
return query.getResultList();
}
}
在通用实体上实现通用持久性函数的抽象外观类。
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public T edit(T entity) {
return getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
您的托管bean将类似于:
@ViewScoped
@ManagedBean
public class MessageBean implements Serializable
{
@EJB
private MessageFacade messageFacade;
private List<Message> messages;
public List<Message> getMessages()
{
return messages;
}
public void setMessages( List<Message> messages )
{
this.messages = messages;
}
@PostConstruct
public void init()
{
messages = messageFacade.findAll();
}
public void onCellEdit( CellEditEvent event )
{
messageFacade.edit(messages);
}
}