...
Code Block |
---|
| java |
---|
| java |
---|
title | 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.
Code Block |
---|
| java |
---|
| java |
---|
title | 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:
Code Block |
---|
| java |
---|
| java |
---|
title | 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();
}
}
}
|
Code Block |
---|
| java |
---|
| java |
---|
title | 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;
this.persistenceUnitName = persistenceUnitName;
}
/*
* 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.