You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

Intro

The Intro page provides an overview, the setup of this module and describes the motivation for the features described below. This page explains the most important APIs and mechanisms of the JPA module provided by CODI. Please note that this page doesn't show all possibilities. If you have any question, please contact the community!

Using one (default) Entity Manager

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

Producer for a default entity manager
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();
        }
    }
}

Hint

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

Using @Transactional
public class CustomService1
{
    @Inject
    protected EntityManager entityManager;

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

Using multiple Entity Managers

Producer for entity managers
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();
        }
    }
}
Using @Transactional and an entity manager with a qualifier
public class CustomService2
{
    @Inject
    @Users
    protected EntityManager entityManager;

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





Extended Persistence Contexts

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.

Usage of a simple ExtendedEntityManager
@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:

Creating a simple ExtendedEntityManager
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();
        }
    }
}
Implementation of a simple ExtendedEntityManager
@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 approach just works if it doesn't come to serialization of this wrapper e.g. in case of session-replication.
If those beans get serialized, you have to overcome this restriction by storing the persistence-unit-name and recreate the EntityManager via Persistence.createEntityManagerFactory(this.persistenceUnitName).createEntityManager(); btw. sync it with the database before closing it on serialization. Furthermore, you have to intercept some methods of the EntityManager to merge detached entities automatically if those entities get serialized as well. However, as mentioned before we don't recommend such an approach.

JTA

Currently there is no support for it, however, you can use https://github.com/openknowledge/openknowledge-cdi-extensions in combination with MyFaces CODI for using JTA (if it works in combination with the application server of your choice).

TransactionScoped (since v1.0.2)

The @Transactional annotation of Apache MyFaces CODI will maintain an own transcaction context which automatically starts when an @Transactional method gets invoked, and ends when the outermost @Transactional method returns. This might for example be used to create @TransactionScoped EntityManagers. The effect of such an EntityManager is similar to using EJBs: when the outermost @Transactional method returns, the @TransactionScoped EntityManager will get destroyed and thus em.close() will get called effectively detaching all entities.

Producer for a @TransactionScoped entity manager
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();
        }
    }
}
  • No labels