Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

The following example will create a CDI producer method for creating a @RequestScoped EntityManager with qualifier @Default.

Code Block
java
java
titleProducer for a default entity managerjava
public class DataBaseProducer
{
    @PersistenceContext(unitName="default")
    private EntityManager entityManager;

    @Produces
    @Default
    @RequestScoped
    public EntityManager createDefaultEntityManager()
    {
        return this.entityManager;
    }

    public void dispose(@Disposes @Default EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
}
Tip
titleHint

For using @PersistenceContext you can use e.g. the resources-plugin of OpenWebBeans

Code Block
java
java
titleUsing @Transactionaljava
//...
public class CustomService1
{
    @Inject
    protected EntityManager entityManager;

    @Transactional
    public void update(CustomEntity1 entity)
    {
        this.entityManager.merge(entity);
    }
}

Using multiple Entity Managers

Code Block
java
java
titleProducer for entity managersjava
public class DataBaseProducer
{
    @PersistenceContext(unitName="default")
    private EntityManager entityManager;

    @PersistenceContext(unitName="UserDB")
    private EntityManager usersEntityManager;

    @Produces
    @Default
    public EntityManager createDefaultEntityManager()
    {
        return this.entityManager;
    }

    @Produces
    @Users
    public EntityManager createUsersEntityManager()
    {
        return this.usersEntityManager;
    }

    public void disposeDefaultDB(@Disposes @Default EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }

    public void disposeUserDB(@Disposes @Users EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
}
Code Block
java
java
titleUsing @Transactional and an entity manager with a qualifierjava
//...
public class CustomService2
{
    @Inject
    @Users
    protected EntityManager entityManager;

    @Transactional(Users.class)
    public void update(CustomEntity2 entity)
    {
        this.entityManager.merge(entity);
    }
}

EntityManager injection without producer (CODI v1.0.3+)

Code Block
java
java
titleUsing @Transactional and @PersistenceContext without producerjava
//...
public class CustomService3
{
    @PersistenceContext(unitName = "default")
    private EntityManager entityManager;

    @Transactional
    public void delete(Entity entity)
    {
        this.entityManager.remove(em.merge(entity));
    }

    @PreDestroy
    public void cleanup()
    {
        if(this.entityManager.isOpen())
        {
            this.entityManager.close();
        }
    }
} 

...

MyFaces Orchestra provides a feature which allows keeping an EntityManager across multiple requests. That means it isn't required to call EntityManager#merge to add detached entities to the context. However, several application architectures don't allow such an approach (due to different reasons like scalability). Seam3 still does that. In theory that sounds nice and it works pretty well for small to medium sized projects esp. if an application doesn't rely on session replication in clusters. That also means that such an approach restricts your target environment from the very beginning. One of the base problems is that an EntityManager isn't serializable. Beans which are scoped in a normalscoped CDI context have to be serializable. So by default it isn't allowed by CDI to provide a producer-method which exposes e.g. a conversation scoped EntityManager as it is. We don't recommend to use this approach and therefore it isn't available out-of-the-box. However, if you really need this approach to avoid calling #merge for your detached entities, it's pretty simple to add this functionality.

Code Block
java
java
titleUsage of a simple ExtendedEntityManagerjava
@Inject
protected EntityManager entityManager;

As you see the usage is the same. You don't have to use ExtendedEntityManager at your injection point. It's just needed in the producer-method:

Code Block
java
java
titleCreating a simple ExtendedEntityManagerjava
public class EntityManagerProducer
{
    @PersistenceContext(unitName = "demoPU")
    private EntityManager entityManager;

    @Produces
    @Default
    @ConversationScoped
    public ExtendedEntityManager create()
    {
        return new ExtendedEntityManager(this.entityManager);
    }

    public void dispose(@Disposes @Default ExtendedEntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
}
Code Block
java
java
titleImplementation of a simple ExtendedEntityManagerjava
@Typed()
class ExtendedEntityManager implements EntityManager, Serializable
{
    private static final long serialVersionUID = 3770954229283539616L;

    private transient EntityManager wrapped;

    protected ExtendedEntityManager()
    {
    }

    public ExtendedEntityManager(EntityManager wrapped)
    {
        this.wrapped = wrapped;
    }

    /*
     * generated
     */
     //delegate all calls to this.wrapped - most IDEs allow to generate it

...

This scope is esp. useful if the loaded entities have to be cached.

Code Block
java
java
titleProducer for a @TransactionScoped entity managerjava
public class DataBaseProducer
{
    @PersistenceContext(unitName="default")
    private EntityManager entityManager;

    @Produces
    @TransactionScoped
    public EntityManager createEntityManager()
    {
        return this.entityManager;
    }

    public void dispose(@Disposes EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
}

...

A solution to this problem is provided via the Apache MyFaces CODI ConfigurableDataSource. This is a thin DataSource wrapper which will get it's configuration via CDI mechanics.

Code Block
XML
XML
titlepersistence.xmlXML
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">

    <persistence-unit name="test" >
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>

        <class>org.apache.myfaces.extensions.cdi.jpa.test.TestEntity</class>

        <properties>
            <property name="openjpa.jdbc.DBDictionary" value="hsql" />
            <property name="openjpa.ConnectionDriverName"
             value="org.apache.myfaces.extensions.cdi.jpa.impl.datasource.ConfigurableDataSource"/>
            <property name="openjpa.ConnectionProperties" value="connectionId=core"/>
        </properties>
    </persistence-unit>
</persistence>

...

Note
titleAttention

Please be aware that this helper only works for @Transactional with the default qualifier! If you need the functionality for another EntityManager, then you need to copy this code and adopt it.

Code Block
XML
XML
titleOptional usage of TransactionHelperXML
MyReslt result = TransactionHelper.getInstance().executeTransactional(new Callable<MyReslt>() {
    public MyReslt call() throws Exception
    {
        EntityManager entityManager = BeanManagerProvider.getInstance().getContextualReference(EntityManager.class);
        entityManager.remove(...);
        return entityManager.find(...);
    }
});