Java 无法刷新注入JSF2托管Bean的JPA2实体
我在会话范围中有一个JSF托管bean,它包含一个要跟踪的实体,例如,经过身份验证的用户:Java 无法刷新注入JSF2托管Bean的JPA2实体,java,jsf-2,dependency-injection,jpa-2.0,Java,Jsf 2,Dependency Injection,Jpa 2.0,我在会话范围中有一个JSF托管bean,它包含一个要跟踪的实体,例如,经过身份验证的用户: @ManagedBean @SessionScoped public class LoginController implements Serializable { User user; public User getUser() { return this.user; } public void setUser(User user) { this.user = use
@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();
}
}
有人能帮我理解这一点吗?如果注入到另一个bean中,为什么会话范围的实体得不到管理?我怎样才能解决这个问题?
谢谢。为了使实体能够刷新,需要对其进行管理,但您已经知道了。 要管理它,它需要
- 重新蚀刻
- 合并然后刷新
- 使用扩展的持久性上下文保持管理
@ManagedBean
和@ViewScoped
都不意味着任何类型的事务管理,因此这些bean中的实体将始终分离,因此您所经历的行为是预期的JPA行为
对于前两个选项,您可以将请求传递给后端中支持事务的EJB,该EJB将合并并更新实体或返回新获取的实体。如果您没有使用JavaEE应用程序服务器,那么可以使用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();
首先,您应该分离您的关注点,这基本上意味着您的支持bean不应该直接执行任何业务逻辑(您的注释
/*一些将其他角色插入数据库的东西暗示了这一点,将用户称为所有者*/
)。相反,您可以使用@EJB
注释在托管bean中注入UserService
类,并通过commandComponents的操作调用其方法
接下来,当您从数据库获取实体并将其与持久性上下文分离时(读:持久性上下文在事务结束时关闭),这意味着该实体不再由持久性服务管理,对实体的更改将不会反映在数据库中。如果要执行此操作,则需要调用EntityManager.merge()
,以使实体持久化。如果希望将LoginController.user
对象中的CANGE持久化到数据库中,则需要执行此操作
因此,Kostja所说的是,当您想要在您的用户对象和数据库中的行之间获得最新的对应关系时,您应该让对象由您的
EntityManager
管理,方法如下。+1。我个人倾向于使用带有后端@EJB
服务的分离对象来完成合并作业和其他工作。或者,如果OP不想处理EJB,可以使用ORM,例如Hibernate,并以编程方式处理事务。对不起,我对java世界不熟悉,目前我使用的jsf有点“开箱即用”,所以我不太确定是否理解了解释,我如何在实践中解决这个问题?我想我的问题是这样解决的:user=em.find(user.getClass(),user.getId())
@Dunadan当然,如果您不希望实体发生任何需要持久化的更改,则重新蚀刻是一个不错的选择。否则,请使用合并。我已经在我的答案中添加了一些例子和细节。好吧,我只是想给你的答案注入更多的解释。
@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();