Pregunta

¿Hay alguna manera de inicializar el EntityManager sin una unidad de persistencia definida?¿Puedes proporcionar todas las propiedades requeridas para crear un administrador de entidad?necesito crear el EntityManager a partir de los valores especificados por el usuario en tiempo de ejecución.Actualizando el persistence.xml y recompilar no es una opción.

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

¿Fue útil?

Solución

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

Deberías definir al menos una unidad de persistencia en el persistence.xml descriptor de implementación.

¿Puedes proporcionar todas las propiedades necesarias para crear un Entitymanager?

  • El atributo de nombre es obligatorio.Los demás atributos y elementos son opcionales.(especificación APP).Entonces este debería ser más o menos tu mínimo. persistence.xml archivo:
<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>

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

Entonces, si su servidor de aplicaciones de destino admite JTA (JBoss, Websphere, GlassFish), su persistence.xml parece:

<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 su servidor de aplicaciones de destino no es compatible con JTA (Tomcat), su persistence.xml parece:

<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á vinculada a un JNDI global (por ejemplo, fuera de un contenedor Java EE), normalmente definiría las propiedades de proveedor, controlador, URL, usuario y contraseña de JPA. Pero El nombre de la propiedad depende del proveedor JPA.Entonces, para Hibernate como proveedor JPA, su persistence.xml el archivo se verá 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>

Atributo de tipo de transacción

En general, en entornos Java EE, un tipo de transacción de RESOURCE_LOCAL asume que se proporcionará una fuente de datos que no sea de JTA.En un entorno Java EE, si no se especifica este elemento, el valor predeterminado es JTA.En un entorno Java SE, si no se especifica este elemento, se aplicará un valor predeterminado de RESOURCE_LOCAL se puede suponer.

  • Para asegurar la portabilidad de una aplicación Java SE, es necesario enumerar explícitamente las clases de persistencia administradas que se incluyen en la unidad de persistencia (especificación JPA)

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

Entonces usa 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);

Otros consejos

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;
}

I fue capaz de crear un EntityManager con Hibernate y PostgreSQL puramente utilizando código Java (con una configuración de primavera) 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 construyó, y luego vuelve getObject() null y que están persiguiendo después NullPointerExceptions 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();

Cuando mi entidad fue 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
}

Aquí hay una solución sin primavera. Las 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 infame 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;
        }
    };
}

Con JPA puro, asumiendo que tiene una aplicación PersistenceProvider (por ejemplo, Hibernate), se puede utilizar el PersistenceProvider # createContainerEntityManagerFactory (información PersistenceUnitInfo, mapa mapa) método para arrancar un EntityManagerFactory sin necesidad de una persistence.xml.

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

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

Cuando el PersistenceUnitInfo se implementa por el resorte-específico clase MutablePersistenceUnitInfo .

este artículo para una buena demostración de cómo se puede lograr este objetivo con Hibernate.

DataNucleus APP que usar también tiene una forma de hacer esto en sus documentos . No hay necesidad de Primavera, o feo implementación de PersistenceUnitInfo.

Simplemente haga lo siguiente

import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;

PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("mydomain.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");

EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top