2010-01-01 17 views
63

¿Hay una manera de inicializar el EntityManager sin una unidad de persistencia definida? ¿Puedes dar todas las propiedades requeridas para crear un administrador de entidades? Necesito crear el EntityManager a partir de los valores especificados por el usuario en el tiempo de ejecución. Actualizar el persistence.xml y volver a compilar no es una opción.Crear APP EntityManager sin el archivo de configuración persistence.xml

Cualquier idea sobre cómo hacer esto es más que bienvenidos!

Respuesta

53

¿Hay alguna manera de inicializar el EntityManager sin una unidad de persistencia definida?

Debe definir al menos una unidad de persistencia en el descriptor de despliegue persistence.xml.

¿Puede dar todas las propiedades necesarias para crear un Entitymanager?

  • El atributo de nombre es obligatorio. Los otros atributos y elementos son opcionales. (Especificación JPA). Por lo que este debe ser más o menos el mínimo persistence.xml archivo:
<persistence> 
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]"> 
     SOME_PROPERTIES 
    </persistence-unit> 
</persistence> 

En entornos Java EE, los jta-data-source y non-jta-data-source elementos se utilizan para especificar el nombre JNDI global de la JTA y/o no Fuente de datos JTA para ser utilizada por el proveedor de persistencia.

Así que si su servidor de aplicaciones de destino admite JTA (JBoss, Websphere, GlassFish), su persistence.xml se parece a:

<persistence> 
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]"> 
     <!--GLOBAL_JNDI_GOES_HERE--> 
     <jta-data-source>jdbc/myDS</jta-data-source> 
    </persistence-unit> 
</persistence> 

Si el servidor de aplicaciones de destino no admite JTA (Tomcat), sus persistence.xml miradas como:

<persistence> 
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]"> 
     <!--GLOBAL_JNDI_GOES_HERE--> 
     <non-jta-data-source>jdbc/myDS</non-jta-data-source> 
    </persistence-unit> 
</persistence> 

Si su fuente de datos no está vinculado a un JNDI mundial (por ejemplo, fuera de un contenedor Java EE), por lo que por lo general se definen proveedor JPA, conductor, u rl, usuario y contraseña. Pero el nombre de la propiedad depende del proveedor de JPA. Así, por Hibernate como proveedor JPA, su persistence.xml archivo se ve así:

<persistence> 
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <class>br.com.persistence.SomeClass</class> 
     <properties> 
      <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver"/> 
      <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/> 
      <property name="hibernate.connection.username" value="APP"/> 
      <property name="hibernate.connection.password" value="APP"/> 
     </properties> 
    </persistence-unit> 
</persistence> 

Tipo Transacción Atributo

En general, en entornos Java EE, un tipo de transacción de RESOURCE_LOCAL supone que un no Se proporcionará el origen de datos de JTA. En un entorno Java EE, si este elemento no está especificado, el valor predeterminado es JTA. En un entorno Java SE, si no se especifica este elemento, se puede suponer un valor predeterminado de RESOURCE_LOCAL.

  • para asegurar la portabilidad de una aplicación Java SE, es necesario incorporar explícitamente las clases de persistencia gestionados que están incluidos en la unidad de persistencia (especificación JPA)

I necesita crear el EntityManager a partir de los valores especificados por el usuario en el tiempo de ejecución

Así que utilice esto:

Map addedOrOverridenProperties = new HashMap(); 

// Let's suppose we are using Hibernate as JPA provider 
addedOrOverridenProperties.put("hibernate.show_sql", true); 

Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties); 
+0

Hola me trataron su solución, pero tienen problemas, ¿podría comprobar mi pregunta: ¿http://stackoverflow.com/ preguntas/3935394/how-to-externalize-properties-from-jpas-persistence-xml – stacker

+0

@stacker Estoy revisando –

21

Sí se puede sin utilizar ningún archivo XML usando la primavera como esta dentro de una clase @Configuration (o su equivalente XML de configuración de la primavera):

@Bean 
public LocalContainerEntityManagerFactoryBean emf(){ 
    properties.put("javax.persistence.jdbc.driver", dbDriverClassName); 
    properties.put("javax.persistence.jdbc.url", dbConnectionURL); 
    properties.put("javax.persistence.jdbc.user", dbUser); //if needed 

    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); 
    emf.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); //If your using eclipse or change it to whatever you're using 
    emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml 
    emf.setPersistenceUnitName(SysConstants.SysConfigPU); 
    emf.setJpaPropertyMap(properties); 
    emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing 
    return emf; 
} 
+0

¿Qué objeto es 'properties'? – ThreaT

+0

es un objeto simple java.util.Properties –

12

yo era capaz de crear una EntityManager con Hibernate y PostgreSQL puramente utilizando código Java (con una configuración de resorte) lo siguiente:

@Bean 
public DataSource dataSource() { 
    final PGSimpleDataSource dataSource = new PGSimpleDataSource(); 

    dataSource.setDatabaseName("mytestdb"); 
    dataSource.setUser("myuser"); 
    dataSource.setPassword("mypass"); 

    return dataSource; 
} 

@Bean 
public Properties hibernateProperties(){ 
    final Properties properties = new Properties(); 

    properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); 
    properties.put("hibernate.connection.driver_class", "org.postgresql.Driver"); 
    properties.put("hibernate.hbm2ddl.auto", "create-drop"); 

    return properties; 
} 

@Bean 
public EntityManagerFactory entityManagerFactory(DataSource dataSource, Properties hibernateProperties){ 
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
    em.setDataSource(dataSource); 
    em.setPackagesToScan("net.initech.domain"); 
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 
    em.setJpaProperties(hibernateProperties); 
    em.setPersistenceUnitName("mytestdomain"); 
    em.setPersistenceProviderClass(HibernatePersistenceProvider.class); 
    em.afterPropertiesSet(); 

    return em.getObject(); 
} 

la llamada a LocalContainerEntityManagerFactoryBean.afterPropertiesSet() es esencial ya que de lo contrario, la fábrica nunca se construye, y luego getObject() devuelve null y está persiguiendo a NullPointerException s durante todo el día. > :-(

A continuación, trabajó con el siguiente código:

PageEntry pe = new PageEntry(); 
pe.setLinkName("Google"); 
pe.setLinkDestination(new URL("http://www.google.com")); 

EntityTransaction entTrans = entityManager.getTransaction(); 
entTrans.begin(); 
entityManager.persist(pe); 
entTrans.commit(); 

Donde mi entidad era la siguiente:

@Entity 
@Table(name = "page_entries") 
public class PageEntry { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 

    private String linkName; 
    private URL linkDestination; 

    // gets & setters omitted 
} 
+1

Buena alternativa para Hibernate. – javydreamercsw

3

Con llanura APP, asumiendo que tiene una aplicación PersistenceProvider (por ejemplo, Hibernate), puede utilizar el método PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) para arrancar un EntityManagerFactory sin necesidad de un persistence.xml.

Sin embargo, es ann oying que hay que implementar la interfaz PersistenceUnitInfo, por lo que es mejor usar la primavera o de hibernación, que tanto apoyo bootstrap APP sin un archivo persistence.xml:

this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
    this.persistenceUnitInfo, 
    getJpaPropertyMap() 
); 

Cuando el PersistenceUnitInfo es ejecutado por la clase específica de Primavera MutablePersistenceUnitInfo.

Consulte this article para obtener una buena demostración de cómo puede lograr este objetivo con Hibernate.

+0

El uso de 'MutablePersistenceUnitInfo' no funciona como algunos métodos [throw UnsupportedOperationException] (https://github.com/spring-projects/spring-framework/blob/4.3.x/spring-orm/src/main/java/org/ springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java # L272-L274). También el [artículo] (https://vladmihalcea.com/2015/11/26/how-to-bootstrap-hibernate-without-the-persistence-xml-file/) mencionado está un poco desactualizado: 'getPersistenceUnitRootUrl' no puede devolver null, de lo contrario, Hibernate no escanea el classpath (Hibernate 5.2.8). – Brice

+0

Estaba un poco equivocado, el artículo no está desactualizado en ese sentido ya que el código está pasando una lista de entidades y no usa el escaneo de paquetes. Sin embargo, para el escaneo automático de entidades es necesario implementar 'getPersistenceUnitRootUrl' o' getJarFileUrls'. El último se siembra en http://stackoverflow.com/a/42372648/48136 – Brice

10

Aquí hay una solución sin Spring. Constantes se toman de org.hibernate.cfg.AvailableSettings:

entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
      archiverPersistenceUnitInfo(), 
      ImmutableMap.<String, Object>builder() 
        .put(JPA_JDBC_DRIVER, JDBC_DRIVER) 
        .put(JPA_JDBC_URL, JDBC_URL) 
        .put(DIALECT, Oracle12cDialect.class) 
        .put(HBM2DDL_AUTO, CREATE) 
        .put(SHOW_SQL, false) 
        .put(QUERY_STARTUP_CHECKING, false) 
        .put(GENERATE_STATISTICS, false) 
        .put(USE_REFLECTION_OPTIMIZER, false) 
        .put(USE_SECOND_LEVEL_CACHE, false) 
        .put(USE_QUERY_CACHE, false) 
        .put(USE_STRUCTURED_CACHE, false) 
        .put(STATEMENT_BATCH_SIZE, 20) 
        .build()); 

entityManager = entityManagerFactory.createEntityManager(); 

y el famoso PersistenceUnitInfo

private static PersistenceUnitInfo archiverPersistenceUnitInfo() { 
    return new PersistenceUnitInfo() { 
     @Override 
     public String getPersistenceUnitName() { 
      return "ApplicationPersistenceUnit"; 
     } 

     @Override 
     public String getPersistenceProviderClassName() { 
      return "org.hibernate.jpa.HibernatePersistenceProvider"; 
     } 

     @Override 
     public PersistenceUnitTransactionType getTransactionType() { 
      return PersistenceUnitTransactionType.RESOURCE_LOCAL; 
     } 

     @Override 
     public DataSource getJtaDataSource() { 
      return null; 
     } 

     @Override 
     public DataSource getNonJtaDataSource() { 
      return null; 
     } 

     @Override 
     public List<String> getMappingFileNames() { 
      return Collections.emptyList(); 
     } 

     @Override 
     public List<URL> getJarFileUrls() { 
      try { 
       return Collections.list(this.getClass() 
              .getClassLoader() 
              .getResources("")); 
      } catch (IOException e) { 
       throw new UncheckedIOException(e); 
      } 
     } 

     @Override 
     public URL getPersistenceUnitRootUrl() { 
      return null; 
     } 

     @Override 
     public List<String> getManagedClassNames() { 
      return Collections.emptyList(); 
     } 

     @Override 
     public boolean excludeUnlistedClasses() { 
      return false; 
     } 

     @Override 
     public SharedCacheMode getSharedCacheMode() { 
      return null; 
     } 

     @Override 
     public ValidationMode getValidationMode() { 
      return null; 
     } 

     @Override 
     public Properties getProperties() { 
      return new Properties(); 
     } 

     @Override 
     public String getPersistenceXMLSchemaVersion() { 
      return null; 
     } 

     @Override 
     public ClassLoader getClassLoader() { 
      return null; 
     } 

     @Override 
     public void addTransformer(ClassTransformer transformer) { 

     } 

     @Override 
     public ClassLoader getNewTempClassLoader() { 
      return null; 
     } 
    }; 
} 
+3

¡Esto me ayudó mucho ya que me ayudó a evitar usar los gastos generales de usar arquillian en algunos casos de prueba! – cljk

Cuestiones relacionadas