2

我在会话范围中有一个 JSF 托管 bean,其中包含一个要跟踪的实体,例如,经过身份验证的用户:

@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();
  }
}

如果我使用 ajax 更新页面someMethodroles列表仍然不会重新加载。如果我在收到此错误em.refresh(user)之前插入:user.getRolesList

Can not refresh not managed object: model.User[ id=1 ].

谁能帮我理解这一点?如果注入另一个 bean,为什么会话范围的实体不受管理?我怎样才能解决这个问题?谢谢你。

4

2 回答 2

7

为了使实体能够刷新,需要对其进行管理,但您已经知道这一点。为了对其进行管理,它需要是

  • 重取
  • 合并然后刷新
  • 通过扩展的持久性上下文保持管理

前两个选项需要交易。

由于既不@ManagedBean也不@ViewScoped暗示任何类型的事务管理,这些 bean 中的实体将始终是分离的,因此您遇到的行为是预期的 JPA 行为。

对于前两个选项,您可以将请求传递给后端启用事务的 EJB,该 EJB 将合并和更新实体或返回新获取的实体。如果您不使用 Java EE 应用程序服务器,则可以使用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();
于 2013-02-25T10:05:10.747 回答
1

First of all, you shall separate your concerns, which basically means that your backing bean should not be performing any business logic directly (which is implied by your comment /* Some stuff that insert other roles into database, referring the user as owner */). Instead, you could inject a UserService class in your managed bean with @EJB annotation and call its methods via actions of your commandComponents.

Next, when you get your entity from a database and detach it from persistence context (read: persistence context is closed at the end of the transaction) it means that the entity is not managed by your persistence service anymore and changes to your entity will not be reflected in the database. If you would want to do so, you will need to call EntityManager.merge(), to make the entity persistent. You will need to do so when you want the canges in your LoginController.user object to be persisted to the database.

So, what Kostja says is when you want to get an up-to-date correspondence between your user object and the row in the database you should make the object managed by your EntityManager, by following one of the ways that he proposed.

于 2013-02-25T11:25:21.057 回答