Search code examples
jpaejbpersistencecdientitymanager

how to dynamically modifying unitName in @PersistenceContext


I'm using JPA 2.1 and I have somthing like this

public class EntityManagerProducer {
    @Produces
    @PersistenceContext(unitName="first_PU")
    private EntityManager em;
    ...

How can I dynamically modify the unitName in @PersistenceContext(unitName = "somer_PU") to use an other entity manager? Is this possible?

VERY IMPORTANT UPDATE

I have a deployed application,the persistence.xml look like this:

<persistence-unit name="db1" transaction-type="JTA">
<jta-data-source>java:/jboss/datasources/PostgresDS</jta-data-source>
<properties>
  <property name="hibernate.hbm2ddl.auto" value="update"/>
  <property name="hibernate.show_sql" value="true"/>
  <property name="hibernate.format_sql" value="true"/>
  <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
  <property name="hibernate.cache.use_second_level_cache" value="false"/>
  <property name="hibernate.jdbc.batch_size" value="50"/>
  <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
  <property name="hibernate.order_inserts" value="true"/>
  <property name="hibernate.order_updates" value="true"/>
  <property name="hibernate.generate_statistics" value="true"/>
  <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
  <property name="jboss.entity.manager.jndi.name" value="java:app/entitymanager/db1"/>
  <property name="jboss.entity.manager.factory.jndi.name" value="java:app/entitymanagerfactory/db1"/>
</properties>

At runtime, could modify the persistence.xml and add another persistence unit but I need a way to get the entitymanager that I need by passing the name of the persistence unit or something, and then using it for what I want. Then I could provide another name of persistence unit and get a different entitymanager. Of course I would like that the transaction process still be container-managed.


Solution

  • Believe me, you don't want to modify the unitName inside existing PersistenceContext. I'm almost sure that all you want to achieve is to have a second EntityManager pointing to a different database, right?

    Then a natural way to go is:

    public class SomeClass {
    
        @PersistenceContext(unitName = "first_PU")
        EntityManager firstEntityManager;
    
        @PersistenceContext(unitName = "somer_PU")
        EntityManager secondEntityManager;
    
        // ...
    }
    

    Personal advices

    1. Please also notice that when using EJB, you don't have to create Producer methods for the EntityManager, as typing @PersistenceContext(...) is enough.

    2. Also following is highly discouraged:

      @Produces
      @PersistenceContext(unitName="first_PU")
      private EntityManager em;
      

      because default scope is @Dependent. Much better would be @RequestScoped or @TransactionScoped.

    3. Instead of hard-coded unit names you can use CDI and annotations qualifiers:

      @Inject
      private @FirstDB EntityManager firstEntityManager;
      
      @Inject
      private @SecondDB EntityManager secondEntityManager;
      

      But then you need to have:

      @Produces
      @RequestScoped // or other
      @FirstDB
      public EntityManager createEntityManagerA() {
          return firstEmf.createEntityManager();
      }
      
      @Produces
      @RequestScoped  // or other
      @SecondDB
      public EntityManager createEntityManagerB() {
          return secondEmf.createEntityManager();
      }
      

    A lot of useful information about CDI and producing multiple EntityManagers you can find here.