【问题标题】:Why entityManager.contains returns different results?为什么 entityManager.contains 返回不同的结果?
【发布时间】:2013-03-10 09:38:15
【问题描述】:

这是在 JPA2 (EclipseLink) 和 JSF2 中。

我有一个实体类 Student:

@Entity
public class Student implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
private int age;

public Student(String firstname, String lastname, int age) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.age = age;
}

public Student() {
}

// accessors and mutators here

}

继承 AbstractFacade 的会话 bean StudentFacade:

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

// other methods: findAll, findRange, count

}

@Stateless
public class StudentFacade extends AbstractFacade<Student> {

@PersistenceContext(unitName = "jpa2testsPU")
private EntityManager em;

@Override
protected EntityManager getEntityManager() {
    return em;
}

public StudentFacade() {
    super(Student.class);
}

public boolean contains(Student s) {
    return getEntityManager().contains(s);
}

public void testContains() {
    Student s = find(1L);
    boolean isContains = getEntityManager().contains(s);
}

}

这是我的 JSF 托管 Bean:

@ManagedBean
@RequestScoped
public class IndexController {

@EJB
private StudentFacade studentFacade;

/**
 * Creates a new instance of IndexController
 */
public IndexController() {
}

public String test() {
    Student s = new Student("John", "Doe", 20);
    studentFacade.create(s);

    Student s1 = studentFacade.find(1L); // This works because table only has 1 record
    boolean isContains = studentFacade.contains(s);

    return null;
}
}

当我从托管 bean 运行 test() 时,isContains 为 false。但是当调用 StudentFacade 中的 testContains() 时,isContains 为真。这是为什么呢?

【问题讨论】:

  • 你能展示一下StudentFacade.contains()的实现吗?我看到 StudentFacade.containsStudent() 但没有看到 contains()。是不是拼错了?
  • 是的,拼错了。

标签: jpa ejb persistence


【解决方案1】:

StudentFacade 是一个无状态会话 Bean (SSB)。不保证其实例变量的内容在方法调用中保留 (reference)。这就像为每个方法调用创建一个不同的 EntityManager 实例。

当您从托管 bean 运行测试时,您在 SSB 上调用了两个不同的方法,因此每次调用都会创建一个不同的 EntityManager 实例,而第二个实例不包含 Student 实例,因为它尚未加载.

但是当您在 SSB 本身的方法中运行测试时,相同的 EntityManager 用于整个方法的范围,因此对 contains() 的调用返回 true。

【讨论】:

  • 我想知道是否因为通过注解@PersistenceUnit 注入而返回了不同的EntityManager 实例。我做了另一个测试:将 EntityManager 暴露给 JSF 托管 bean,然后调用 entityManager.persist,抛出 TransactionRequiredException。这表明注入在 SSB 上下文和 JSF 托管 bean 上下文中的解析方式不同。
  • JSF @ManagedBean 不受管理。 1. 只有将 ManagedBean 做成 EJB,如@Stateless,才能注入@PersistenceContext EntityManager。 2.你可以注入@PersistenceUnit EntityManagerFactory和@Resource UserTransaction
猜你喜欢
  • 2012-07-28
  • 1970-01-01
  • 2017-04-01
  • 2010-10-31
  • 2013-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多