2011-08-20 90 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。

也就是说,通常情况下是一个维尼特描述你在哪里得到分离实体。