Ludovic,
I don't know if it may be of some help for you, but we have a lot of seam2 apps that we migrated to CDI and we had to face the
problems you describe (With many other..)
We tried first to use CODI then DeltaSpike, in its early days but we ended to
create our own CDIUtils libs..
To solve the problem, we exposed the EM in RequestScoped but it is kept
internally a ConversationScoped Bean holder:
So when a LRC is on, we always get the same EM
@ConversationScoped
public class EntityManagerProducer {
private transient EntityManager em;
@PersistenceUnit
private EntityManagerFactory emf;
@Produces
@RequestScoped
protected EntityManager creerEntityManager() {
// On n'a pas de EM en scope conversation, on en récupère un...
if (em == null) {
em = emf.createEntityManager();
}
return this.em;
}
@PreDestroy
public void terminer() {
if (em != null) {
if (em.isOpen()) {
log.trace("close em {}", em);
em.close();
}
}
em = null;
}
}
Also the EM is not directly injected into Beans as our "Business Objects" are held in a jar and the jar may be used in 3 different
contexts:
- online/web in EJB3 SFSB,SLSB
- online in MDB or Web Services beans (No conversationscope here, but
@PersistenceUnit IS available)
- in batchs/JUnit (No conversationscope here, and no@PersistenceUnit available
from J2SE)
We have an interface called "EMResolver" that is injected in BO beans:
public interface EntityManagerResolver {
EntityManager getEm();
}
with 2 different implentations, one onlie, one for batchs (that is declared as
an @Alternative)
The online implementation is:
@Stateless
public class EntityManagerResolverOnline implements EntityManagerResolver {
@PersistenceContext
private EntityManager emFromEJB;
@Inject
private Instance<EntityManager> emLazyInstance;
public EntityManager getEm() {
Boolean estMDBouWS = ThreadLocalContextHolder.isMDBorWS();
if (estMDBouWS) {
log.trace("Contexte online MDB ou WS - EntityManager vient de
@PersistenceContext.");
return emFromEJB;
} else {
log.trace("Contexte online non MDB ni WS - EntityManager vient de CDI.
+joinTransaction");
EntityManager em = emLazyInstance.get();
em.joinTransaction();
return em;
}
}
}
The ThreadLocalContextHolder keep a boolean "threadlocal" variable set by MDBs
(from MDB own superclass) or WS (JAX-WS own handler)
The batch implementation:
@Alternative
@ApplicationScoped
public class EntityManagerBatchResolver implements EntityManagerResolver {
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct
public void initialiser() {
log.debug("@PostConstruct. Utilisation de EntityManagerBatchResolver");
emf = Persistence.createEntityManagerFactory(<name of the PU here>);
em = emf.createEntityManager();
}
@PreDestroy
public void terminer() {
log.debug("@PreDestroy. terminer");
emf.close();
}
public EntityManager getEm() {
return em;
}
}
Maybe it is not very academic but it works perfectly well for us and made our
move from seam 2 smotth..
Hope this helps..
Denis
Le 2015-04-17 05:37, [email protected] a écrit :
Dear all,
I am actually trying to switch from "raw" Hibernate to JPA.
I have the typical "keep the same entitymanager" during a scenario problem. IMHO, merging huge collections of entities is a
nightmare that is not worth the cost when you deal with applications with a lot of business logic but few users and a low load. I
fully endorse the "entitymanager per request" pattern for application having high trafic, and so need to be stateless, replicated,
etc. but it does not appear to me to be the magic solution to all problems.
With hibernate, I historically solved it with the "open session in view" pattern. It is ugly when evaluated according to actual
standards, but it works.
https://developer.jboss.org/wiki/OpenSessionInView
When I tried to find the equivalent for JPA, I basically found
@PersistenceContext(type=PersistenceContextType.EXTENDED)
...which could be a fit if I was using container managed datasources
When digging the Hibernate 4.3.8 jpa implementation, I noticed that when I use application managed EntityManager-s, they are all
created with PersistenceContextType.EXTENDED, and that this attribute is finally passed to :
AbstractEntityManagerImpl base class constructor :
protected AbstractEntityManagerImpl(
EntityManagerFactoryImpl entityManagerFactory,
PersistenceContextType type, // TODO: remove as no longer used
SynchronizationType synchronizationType,
and is just ignored. :-)
On this blog (I like good authors ;-) ) https://struberg.wordpress.com/2012/04/25/is-there-a-way-to-fix-the-jpa-entitymanager/ , I
found mention of Avaje, which could be a fit if it was more of a standard.
I also fond on the net references to CODI, MyFaces Orchestra and Seam solutions to this problem. Most of the type it was also
indicated that Deltaspike is "the way to go". An affirmation that is clearly also mine in general.
However, I did not find a ready-to-use solution in the doc
http://deltaspike.apache.org/documentation/jpa.html#_extended_persistence_contexts
I was a bit surprised, as some people stated that Seam code was to be merged in
Deltaspike not to find a turn key solution.
Did I miss / misunderstood something ?
This is not a blocking problem to me. I can just use plain hibernate or unwrapped jpa/hibernate sessions and it will work... But I
would like to understand. :-)
Thanks in advance,
Ludovic
|
| AVANT D'IMPRIMER, PENSEZ A L'ENVIRONNEMENT.
|