Tiny
Tiny

Reputation: 27899

Using different entity managers in different EJBs within the same single transaction

Employee employee = entityManager.find(Employee.class, 1L);

if (employee == null) {
    throw new EntityNotFoundException();
}

Since EntityManager#find() returns null in case, the said entity is unavailable, the conditional test as shown above is necessary to avoid the possible java.lang.NullPointerException which is otherwise likely. Repeating this trivial conditional test everywhere is pretty much unacceptable and discouraged which makes the business logic which should in turn be as simple as possible, pretty much unreadable.

To prevent this conditional check from being repeated all over the place, I have a generic method in a separate EJB like so,

@Stateless
public class EntityManagerUtils implements EntityManagerService {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public <T extends Object> T find(Class<T> entityClass, Object primaryKey) {
        T entity = entityManager.find(entityClass, primaryKey);

        if (entity == null) {
            throw new EntityNotFoundException();
        }

        return entity;
    }
}

Invoking this method from inside another EJB like the following,

@Stateless
public class TestBean implements TestBeanService {

    @PersistenceContext
    private EntityManager entityManager;

    @Inject
    private EntityManagerService entityManagerService;

    @Override
    public void test(Employee employee) {
        Department managedDepartment = entityManagerService.find(Department.class, employee.getDepartment().getDepartmentId());
        System.out.println("contains : " + entityManager.contains(managedDepartment));
    }
}

Here, despite the fact that everything happens within the same single transaction, entityManager.contains(managedDepartment) returns true i.e. the returned Department entity is managed by both the EntityManagers in both the EJBs.

Although it is expected, how does entityManager.contains(managedDepartment) return true?

Is it the same EntityManager instance using the same EntityManagerFactory?

Upvotes: 1

Views: 992

Answers (1)

V G
V G

Reputation: 19002

I doubt the EJB specification guarantees that the EntityManager Java instances will be the same, but it guarantees they are backed by the same Persistence Context (the same set of managed entities), because you are in the same JTA transaction and because both EntityManagers are container managed of the same persistence unit (the default in your case).

If you want to check whether the instances are the same in your environment, check the output of

System.out.println("EntityManager : " + entityManager);

but I would not rely on that as a guarantee for future versions of your Application Server.

If you want a new Persistence Context, you could either begin a new transaction or create manually an EntityManager instance from an injected EntityManagerFactory.

For performace considerations, I wouldn't want to use a new Persistence Context in your situation.

Edit: Add a quote from official JavaEE 7 Tutorial that explains/justify what it was just said

The persistence context is automatically propagated with the current JTA transaction, and EntityManager references that are mapped to the same persistence unit provide access to the persistence context within that transaction. By automatically propagating the persistence context, application components don't need to pass references to EntityManager instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers.

Upvotes: 4

Related Questions