¿Cómo usar la clase Hibernate SchemaUpdate con un JPA persistence.xml?
(3)
Debe usar Ejb3Configuration en lugar de la configuración normal . Consulte la documentación del administrador de la entidad, al final de la sección de arranque en la documentación de hibernación.
(Copiado de la fuente anterior con adaptaciones menores)
Ejb3Configuration cfg = new Ejb3Configuration();
EntityManagerFactory emf =
cfg.addProperties(properties) // add some properties
.setInterceptor(myInterceptorImpl) // set an interceptor
.addAnnotatedClass(MyAnnotatedClass.class) // add a class to be mapped
.addClass(NonAnnotatedClass.class) // add an hbm.xml file using the Hibernate convention
.addResource("mypath/MyOtherCLass.hbm.xml") // add an hbm.xml file
.addResource("mypath/orm.xml" ) // add an EJB3 deployment descriptor
.configure("/mypath/hibernate.cfg.xml") // add a regular hibernate.cfg.xml
.buildEntityManagerFactory(); // create the entity manager factory
Como puede ver, puede mezclar muchos tipos diferentes de configuración.
Si solo es para la parte de actualización del esquema, puede establecer una propiedad en su persistence.xml: hibernate.hbm2ddl.auto
:
<persistence-unit name="app1">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
…
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</properties>
Vea here para algunas referencias más.
Tengo un método principal que usa SchemaUpdate para mostrar en la consola qué tablas alterar / crear y funciona bien en mi proyecto de Hibernate:
public static void main(String[] args) throws IOException {
//first we prepare the configuration
Properties hibProps = new Properties();
hibProps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jbbconfigs.properties"));
Configuration cfg = new AnnotationConfiguration();
cfg.configure("/hibernate.cfg.xml").addProperties(hibProps);
//We create the SchemaUpdate thanks to the configs
SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);
//The update is executed in script mode only
schemaUpdate.execute(true, false);
...
Me gustaría reutilizar este código en un proyecto JPA, no teniendo ningún archivo hibernate.cfg.xml (y ningún archivo .properties), sino un archivo persistence.xml (detectado automáticamente en el directorio META-INF como se especifica en la especificación JPA) .
He intentado esta adaptación demasiado simple,
Configuration cfg = new AnnotationConfiguration();
cfg.configure();
pero falló con esa excepción.
Exception in thread "main" org.hibernate.HibernateException: /hibernate.cfg.xml not found
¿Alguien ha hecho eso? Gracias.
Kariem está en el camino correcto, pero permítame aclarar.
Supongamos que tiene una configuración estándar de vainilla JPA sin nada específico de Hibernate, excepto los tarros de Hibernate en el classpath. Si está ejecutando en modo bootstrap J2SE, ya tiene algo de código que se parece a esto, ya sea en Java o como configuración de Spring, etc .:
Map<String, Object> props = getJPAProperties();
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("persistence-unit-name", props);
Para ejecutar SchemaUpdate, simplemente use esto en su lugar:
Map<String, Object> props = getJPAProperties();
Ejb3Configuration conf =
new Ejb3Configuration().configure("persistence-unit-name", props);
new SchemaUpdate(conf.getHibernateConfiguration()).execute(true, false);
No estoy seguro de cómo funcionaría esto en un entorno de contenedor, pero en una configuración simple tipo J2SE o Spring, eso es todo.
Muchas gracias Peter, tu respuesta funcionó bien. Aquí está el código completo de nuestra clase SchemaUpdater:
package reformyourcountry.dbupdate;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import reformyourcountry.misc.DateUtil;
/** Small utility to be run by a developer to identify the difference between
* its entities and its DB schema. It produces an SQL to be copy/pasted and applied
* on the DB manually. Each developers having its own DB, when a developer commits its
* Java code with new entity attributes (needing new DB columns), he also commits
* an updated SQL file with the SQL that other developers need to apply on their local DB.
* Later, when deploying the next version of the application in production,
* this SQL file with cumulated changes will be applied onto the production DB.
*
* Limitations:
* 1. the Hibernate schema update does not detect removed attributes.
* If you have to delete a column, you need to write the SQL manually;
*
* 2. the Hibernate schema update does not detect changes on existing columns.
* for example, if you add @Column(nullable=false), it will not generates an
* additional DB constraint.
*
* @author Cédric Fieux & John Rizzo & Aymeric Levaux
*
*/
public class SchemaUpdater {
@SuppressWarnings({ "deprecation", "unchecked" })
public static void main(String[] arg) throws IOException {
////// 1. Prepare the configuration (connection parameters to the DB, ect.)
// Empty map. We add no additional property, everything is already in the persistence.xml
Map<String,Object> map=new HashMap<String,Object>();
// Get the config from the persistence.xml file, with the unit name as parameter.
Ejb3Configuration conf = new Ejb3Configuration().configure("ConnectionPostgres",map);
SchemaUpdate schemaUpdate =new SchemaUpdate(conf.getHibernateConfiguration());
/////// 2. Get the SQL
// Before we run the update, we start capturing the console output (to add ";" later)
PrintStream initOut = System.out;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
PrintStream newOut = new PrintStream(outputStream);
System.setOut(newOut);
//The update is executed in script mode only
schemaUpdate.execute(true, false);
//We reset the original out
System.setOut(initOut);
////// 3. Prints that SQL at the console with a good format (adding a ";" after each line).
System.out.println("--*******************************************Begin of SQL********************************************");
System.out.println("-- "+DateUtil.formatyyyyMMdd(new Date()));
BufferedReader ouReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
String str = ouReader.readLine();
while(str != null){ // For each (sometimes multiline) SQL statement
// now, str equals "".
str = ouReader.readLine(); //
while (str != null && !str.trim().equals("")) { // for each line of the same statement
System.out.println(); // previous line is finished.
System.out.print(str.toLowerCase());
str = ouReader.readLine();
}
// Statement is now finished
System.out.println(";");
}
System.out.println("--*******************************************End of SQL********************************************");
////// 4. Print eventual exceptions.
//If some exception occurred we display them
if(!schemaUpdate.getExceptions().isEmpty()){
System.out.println();
System.out.println("SOME EXCEPTIONS OCCURED WHILE GENERATING THE UPDATE SCRIPT:");
for (Exception e: (List<Exception>)schemaUpdate.getExceptions()) {
System.out.println(e.getMessage());
}
}
}
}