martes, abril 06, 2010

JPA: Modificar unidades de persistencia programáticamente

Si trabajáis con JPA, nosotros concretamente con Netbeans (aunque en Eclipse funciona de forma similar), durante el desarrollo de las aplicaciones, procedemos a crear un modelo de datos y a desplegar el modelo físico sobre nuestro motor de base de datos.

En el caso de Netbeans, mediante wizards, creamos nuestra conexión, la unidad de persistencia ("persistence.xml") y podemos generar nuestras entidades a partir del modelo físico.

¿Y el proceso inverso?. Supongamos que ya tenemos nuestra aplicación y lo que queremos es que al desplegar nuestra aplicación en los servidores de producción, en base a nuestras entidades, se recree la base de datos, sin necesidad de hacer una importación (debe existir el esquema y el usuario, por supuesto, pero no es preciso importar las tablas "manualmente").

Esto es posible modificando programáticamente una unidad de persistencia existente en el archivo "persistence.xml". Con un poco de trabajo, se puede crear un "wizard" en nuestra aplicación que detecte si la instalación es nueva y que sea capaz de recrear las tablas en base a nuestras entidades ya existentes.

Al menos, esta es la forma que hemos encontrado de hacerlo... es posible que haya formas mejores.

(Este ejemplo enlaza con el post anterior sobre el motor InnoDB de MySQL. En nuestro caso, las tablas originales eran InnoDB, pero cuando se recreaban las tablas en otro esquema, aparecían como MyISAM.)

En el ejemplo, uso TopLink Essentials, de Oracle. Las propiedades para Hibernate o EclipseLink, varían.

Este sería nuestro archivo "persistence.xml". Como véis, no tiene propiedades. Sólamente declaramos el nombre de la unidad, el proveedor y las entidades, pero no las propiedades:


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<class>test.entities.Entidad2</class>
<class>test.entities.Entidad1</class>
</persistence-unit>
</persistence>


Modificar la unidad de persistencia pasando las propiedades programáticamente, es simple:


Properties props = new Properties();
props.put(TopLinkProperties.JDBC_USER,"user");
props.put(TopLinkProperties.JDBC_PASSWORD,"password");
props.put(TopLinkProperties.JDBC_URL,"jdbc:mysql://hostname:3306/targetddbb?sessionVariables=storage_engine=InnoDB");
props.put("toplink.ddl-generation","create-tables");
props.put(TopLinkProperties.JDBC_DRIVER,"com.mysql.jdbc.Driver");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnit",props);
EntityManager em = emf.createEntityManager();
em.close();
emf.close();


Si os fijáis, hay una propiedad "toplink.ddl-generation", con el valor "create-tables". Esto hace que al instanciar el objeto EntityManager, se regeneren las tablas en la base de datos, en base a las entidades declaradas en "persistence.xml" y asociadas a la unidad "PersistenceUnit". Es decir, sólo con ejecutar este código, se regeneran las tablas.

Por último insistir en que para realizar las pruebas, hemos usado:

- Netbeans 6.8
- TopLink Essentials
- MySQL

Los esquemas de origen y destino de nuestras tablas eran MySQL. No hemos probado a regenerar las tablas en una base de datos distinta...

4 comentarios:

Anónimo dijo...

excelente codigo... me queda una duda... el Properties de que libreria le importo?

Unknown dijo...

Hola, he utilizado tu publicacion en mi alicacion, tengo una alicacion donde utilizo como motor de persistencia Toplink, y dado una direccion de servidor modifico las propiedades de la unidad de persistencia, he hecho un debug y aparentemente me toma los cambios en el Entity Manager Factory, pero al momento de crear el entity manager me tira el siguiente error:


Exception in thread "AWT-EventQueue-0" Local Exception Stack:
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: No suitable driver found for jbc:mysql://10.115.33.2:3306/dvpdggb_v2_prueba
Error Code: 0
at oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:305)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:102)
at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:184)
at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:582)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:280)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:229)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:93)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:126)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:120)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:91)


he revisado la librerias y estan bien, he copiado la libreria en el directorio java/jre6/lib/ext y java/jre7/lib/ext pero nada..


espero puedan ayudarme! gracias

Unknown dijo...

Para Beta Martinez...

No sé si será un error o es así como lo tienes configurado, pero yo creo que la cadena de conexión debería ser comenzar por "jdbc:mysql..." y no por "jbc:mysql".

También deberías asegurarte de que el driver se encuentra bien ubicado en el servidor.

Unknown dijo...

no puedo explicarte la cantidad de cosas qe hice para solucionar el problemas... hasta edición del archivo xml linea por linea... evidentemente estaba muy cansada como para ver tan TONTO error! ... muchas gracias... me fueron de muchisima ayuda!