Reputation: 3175
I have a database with multiples schemas so I have a persistence.xml file with multiples <persistence-unit />
(named 01, 02, ...).
Problematic : I want to create an EntityManager dynamically function of some user criteria.
I have tested 2 cases.
First case : basically, I tested this code (inside stateless EJB) :
String criteria = "01";
EntityManagerFactory emf = Persistence.createEntityManagerFactory(criteria);
EntityManager em = emf.createEntityManager();
Joueur joueur = new Joueur(); // Joueur is an Entity
joueur.setPseudo("olivier");
em.persist(joueur);
but I received exception :
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: org.postgresql.util.PSQLException: ERREUR: la transaction est annulée, les commandes sont ignorées jusqu'à la fin du bloc de la transaction
I thought, (with help of some Stackoverflow posts), that my EntityManager wasn't "linked" to my transaction context due to the fact it wasn't injected by container.
Second case : thus, I used injection :
@PersistenceContext(unitName="00")
private EntityManager em00;
@PersistenceContext(unitName="01")
private EntityManager em01;
Code in my function :
String criteria = "01";
EntityManager em = getEm(criteria);
...
and getEm() method :
private EntityManager getEm(String criteria){
if (criteria == "00")
return em00;
else if (criteria == "01")
return em01;
return null;
}
No problem, it's work but I have to inject as many EntityManagers that I have persistence-unit.
Thank you for advices and feedbacks
EDIT :
My configurations files :
Persistence.xml :
<persistence version="2.0"
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_2_0.xsd">
<persistence-unit name="00" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/sim/00</jta-data-source>
<mapping-file>orm_00_beta.xml</mapping-file>
<class>com.sim.entities.Joueur</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
<persistence-unit name="01" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/sim/01</jta-data-source>
<mapping-file>orm_01_beta2.xml</mapping-file>
<class>com.sim.entities.Joueur</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
</persistence>
orm_00_beta.xml :
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>beta</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
orm_01_beta2.xml :
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>beta2</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
Upvotes: 4
Views: 3743
Reputation: 18389
You need to set the "eclipselink.target-server" to the application server you are using when using application managed persistence units (some servers set this automatically then using container managed persistence units). Then the EntityManager will bind with the JTA transaction that is active when it is created. If you create the EntityManager before the start of the JTA transaction then you can use joinTransaction().
If you still have issues, include the server you are using, and the full exception stack trace.
If you have a lot of schemas, you could consider using EclipseLink multi-tenant support, which allows each tenant to have their own schema.
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ
Upvotes: 2
Reputation: 9162
Usually you don't have 50 schemas. I would not worry about the cost of injections, as usually EJB container has a pool of already opened connections which are ready to be injected. So the overhead is really small.
AFAIK, JPA does not allow dynamic entity managers.
If you care about resources, I would suggest to avoid using EclipseLink (I had really bad experience with EclipseLink + EJBs)
To optimize things a bit I would try to use factory pattern here. Create a Bean which will serve you EntityManagers. Instead of injecting several PersistenceContext you will have one injection with a method like:
EntityManager getEntityManager(String schemaId) {...}
Another option is to move all injections to an AbstractBean. All other beans inherit from the AbstractBean.
Upvotes: 1