0

Actually I want to migrate a Seam 2 application to Java EE 7 with CDI and are trying to imitate the behavior of the Seam Home Component.

I am creating a application-managed EntityManager with a CDI producer and want to use it in a @ConversationScoped bean. I have defined my own EntityManager as a serializable wrapper around the default EntityManager implementation, which is just calling the methods of the delegate. The CDI producer looks as follows:

@ApplicationScoped
public class EntityManagerProducer
{
    @PersistenceUnit(unitName = "showcase")
    private EntityManagerFactory emFactory;

    @Produces
    @RequestScoped
    public EntityManager createEntityManager()
    {
        return new ExtendedEntityManager(emFactory.createEntityManager());
    }

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

Do I need to define my conversationscoped Home component as @Stateful? An entity which was loaded by findon the injected entity manager is in a second step of the conversation not longer managed. A call of joinTransactiondoes not reattach the entity to the current EntityManager.

Edit:

I want to give some more information about the use case I am facing: As mentioned I want to imitate the Home component of Seam 2. So I created a own Home super class with CRUD methods for creating, updating and removing an entity. In the method for updating an entity I use following code:

public String update()
{
    try
    {
        joinTransaction();
        E tmp = getEntityManager().merge(getInstance());

        setInstance(tmp);
        getEntityManager().flush();

        // updatedMessage();
        // raiseAfterTransactionSuccessEvent();
    }
    catch (Exception ex)
    {
        log.error("error occured: ", ex);
    }
    return "updated";
}

public void joinTransaction() {
    log.debug("joining transation if EntityManager is open and not joined");
    if (getEntityManager().isOpen() && !getEntityManager().isJoinedToTransaction())
    {
        log.debug("joining transaction");
        getEntityManager().joinTransaction();
    }
}

If I call joinTransaction I can see in the log that getEntityManager().joinTransaction() is called. But this gives me the exception:

javax.persistence.TransactionRequiredException: Explicitly joining a JTA transaction requires a JTA transaction be currently activ

If I comment the line jooinTransaction() I'll get the following exception on the method call getEntityManager().flush():

javax.persistence.TransactionRequiredException: no transaction is in progress

So the problem is, that I would like to call flush and only then the entity should be persisted in database.

Georg Leber
  • 3,470
  • 5
  • 40
  • 63
  • two questions: 1. So you want to get rid of the ejb-container. That means there is no JTA-Context anymore? 2. using merge or persist you make an entity managed. You cannot expect an entity to be automatically managed just by doing new or if the generating transaction was ended. could you show the code where you do the merge ? – aschoerk Nov 11 '17 at 11:56
  • The only way a conversation can work is if you do persistence in an isolated transaction at the end of it, trying to maintain a managed entity across the different requests is madness especially when you recreate a fresh transaction for each request. I know, I've been there with the exact same "Need to make it work like Seam 2 did" reason. Seam 2 however binds an entity manager to the conversation and keeps the transaction alive; it can do that because among the many mechanisms was a manager which could detect and cleanup abandoned conversations. – Gimby Nov 13 '17 at 14:14
  • So @Gimby: You would recommend to use an injected EntityMananer (produced like in my code) and then e.g. for the update method use something like `return getEntityManager().merge(entity);` with the method annotated with `@TransactionAttribute(TransactionAttributeType.REQUIRED)`? – Georg Leber Nov 13 '17 at 14:55
  • For the persistence part it boils down to that yes. Depends on your code and object model, you may still need an entity manager per request to be able to fetch data you will want to populate into the entity/DTO. – Gimby Nov 13 '17 at 16:06

0 Answers0