2013-03-21 4 views
0

Это в JPA2 (EclipseLink) и JSF2.Почему entityManager.contains возвращает разные результаты?

У меня есть класс объект 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 

} 

Session Bean StudentFacade, который наследуется AbstractFacade:

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

Когда я запускаю тест() из управляемого компонента, isContains является ложным. Но когда вызывается testContains() в StudentFacade, isContains истинно. Почему это?

+0

Можете ли вы продемонстрировать реализацию StudentFacade.contains()? Я вижу StudentFacade.containsStudent(), но не содержит(). Это просто неправильно? –

+0

Да, это неправильно. – Cam

ответ

1

StudentFacade - это бесконфликтный сеанс (SSB). Содержимое переменных экземпляра не гарантируется для всех вызовов методов (reference). Это похоже на наличие другого экземпляра EntityManager, созданного для каждого вызова метода.

Когда вы запускаете свой тест из управляемого компонента, вы вызываете два разных метода на SSB, поэтому для каждого вызова создается другой экземпляр EntityManager, а второй не содержит экземпляр Student, поскольку он не был загружен все же.

Но когда вы запускаете свой тест внутри метода самого SSB, тот же EntityManager используется для области всего метода, поэтому вызов to contains() возвращает true.

+0

Интересно, были ли возвращены разные экземпляры EntityManager из-за инъекции через аннотацию @PersistenceUnit. Есть еще один тест, который я сделал: при представлении EntityManager в управляемый bean-компонент JSF, тогда вызов bodyManager.persist был выведен из TransactionRequiredException. Это показало, что инъекция была решена по-разному в контексте SSB и в контексте управляемого JSF компонента. – Cam

+0

JSF @ManagedBean не управляется. 1. Вы можете ввести '@PersistenceContext EntityManager', только если вы сделали ManagedBean в EJB с помощью' @ Stateless'. 2. Вы можете ввести '@PersistenceUnit EntityManagerFactory' вместе с' @Resource UserTransaction' –

Смежные вопросы