2015-11-13 11 views
5

Ich habe versucht, diese Klasse mit:Hibernate 5. Generieren von SQL DDL in die Datei

Hibernate/JPA: Check generated sql before updating DB Schema (like .NET EF migrations)

Ich habe den folgenden Code:

package com.mypackage.jpa.util; 

import java.io.File; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 

import org.hibernate.cfg.Configuration; 
import org.hibernate.tool.hbm2ddl.SchemaExport; 

public class SchemaGenerator { 

    private Configuration cfg; 

    public static void main(String[] args) throws Exception { 

     File f = new File("."); 
     String directory = f.getAbsoluteFile() + "/src/main/resources/ddl/generated/"; 

     String packageName[] = { "com.mypackage.jpa", "com.mypackage.jpa.legacy", "com.mypackage.jpa.local", 
       "com.mypackage.jpa.local.impl" }; 

     SchemaGenerator gen = new SchemaGenerator(packageName); 
     gen.generate(Dialect.MYSQL, directory); 

    } 

    @SuppressWarnings("rawtypes") 
    public SchemaGenerator(String[] packagesName) throws Exception { 
     cfg = new Configuration(); 
     cfg.setProperty("hibernate.hbm2ddl.auto", "create"); 

     for (String packageName : packagesName) { 
      for (Class clazz : getClasses(packageName)) { 
       cfg.addAnnotatedClass(clazz); 
      } 
     } 
    } 

    @SuppressWarnings("rawtypes") 
    private List<Class> getClasses(String packageName) throws Exception { 
     File directory = null; 
     try { 
      ClassLoader cld = getClassLoader(); 
      URL resource = getResource(packageName, cld); 
      directory = new File(resource.getFile()); 
     } catch (NullPointerException ex) { 
      throw new ClassNotFoundException(packageName + " (" + directory + ") does not appear to be a valid package"); 
     } 
     return collectClasses(packageName, directory); 
    } 

    private ClassLoader getClassLoader() throws ClassNotFoundException { 
     ClassLoader cld = Thread.currentThread().getContextClassLoader(); 
     if (cld == null) { 
      throw new ClassNotFoundException("Can't get class loader."); 
     } 
     return cld; 
    } 

    private URL getResource(String packageName, ClassLoader cld) throws ClassNotFoundException { 
     String path = packageName.replace('.', '/'); 
     URL resource = cld.getResource(path); 
     if (resource == null) { 
      throw new ClassNotFoundException("No resource for " + path); 
     } 
     return resource; 
    } 

    @SuppressWarnings("rawtypes") 
    private List<Class> collectClasses(String packageName, File directory) throws ClassNotFoundException { 
     List<Class> classes = new ArrayList<>(); 
     if (directory.exists()) { 
      String[] files = directory.list(); 
      for (String file : files) { 
       if (file.endsWith(".class")) { 
        // removes the .class extension 
        classes.add(Class.forName(packageName + '.' + file.substring(0, file.length() - 6))); 
       } 
      } 
     } else { 
      throw new ClassNotFoundException(packageName + " is not a valid package"); 
     } 
     return classes; 
    } 

    private void generate(Dialect dialect, String directory) { 
     cfg.setProperty("hibernate.dialect", dialect.getDialectClass()); 
     SchemaExport export = new SchemaExport(cfg); 
     export.setDelimiter(";"); 
     export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql"); 
     export.setFormat(true); 
     export.execute(true, false, false, false); 
    } 

    private static enum Dialect { 
     ORACLE("org.hibernate.dialect.Oracle10gDialect"), MYSQL("org.hibernate.dialect.MySQLDialect"), HSQL(
       "org.hibernate.dialect.HSQLDialect"), H2("org.hibernate.dialect.H2Dialect"); 

     private String dialectClass; 

     private Dialect(String dialectClass) { 
      this.dialectClass = dialectClass; 
     } 

     public String getDialectClass() { 
      return dialectClass; 
     } 
    } 
} 

Und bekomme ich folgende Fehlermeldung:

Exception in thread "main" java.lang.UnsupportedOperationException: Attempt to use unsupported SchemaExport constructor accepting org.hibernate.cfg.Configuration; one of the forms accepting org.hibernate.boot.spi.MetadataImplementor should be used instead at org.hibernate.tool.hbm2ddl.SchemaExport.(SchemaExport.java:250) at cu.x.util.SchemaGenerator.generate(SchemaGenerator.java:116) at cu.x.util.SchemaGenerator.main(SchemaGenerator.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

Ich ändere meinen Code mit den folgenden:

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build(); 
MetadataImplementor metadataImplementor = (MetadataImplementor) 
     new MetadataSources(serviceRegistry).buildMetadata(); 
SchemaExport export = new SchemaExport(metadataImplementor); 

Aber es generiert eine leere .SQL-Datei. Ich verwende annotierte Klassen. Was könnte passieren?

+0

Ja, meine Muttersprache ist Spanisch. Ich kann perfekt Englisch lesen, aber schlecht schreiben. In meiner Arbeit muss man nur auf Englisch lesen, nicht schreiben oder sprechen. – felix

+0

Meine Entschuldigung, das sollte eine Bemerkung über den Grund meiner Bearbeitungen sein. Ich habe nicht versucht, dein Englisch unnötig zu beleidigen. – leigero

Antwort

6

Offenbar kann die Configuration-Klasse nicht verwendet werden. Wir müssen die MetadataSources-Klasse verwenden, um die annotierten Klassen hinzuzufügen.

private void generate(Dialect dialect, String directory, String[] packagesName) throws Exception { 

    MetadataSources metadata = new MetadataSources(
      new StandardServiceRegistryBuilder() 
        .applySetting("hibernate.dialect", dialect.getDialectClass()) 
        .build()); 

    for (String packageName : packagesName) { 
     log.info("packageName: " + packageName); 
     for (Class clazz : getClasses(packageName)) { 
      log.info("Class: " + clazz); 
      metadata.addAnnotatedClass(clazz); 
     } 
    } 

    SchemaExport export = new SchemaExport(
      (MetadataImplementor) metadata.buildMetadata() 
    ); 

    export.setDelimiter(";"); 
    export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql"); 
    export.setFormat(true); 
    export.execute(true, false, false, false); 
} 
+0

Hallo Felix, ich stieß auf ein ähnliches Problem und fand auch eine Lösung. Vielleicht hilft es Ihnen auch: http://stackoverflow.com/a/41894432/974186 –

1

Die Lösung von felix funktionieren nicht mehr auf Hibernate 5.2

hier ist eine Version, die kompatibel si private void erzeugen (Klasse Dialekt, String Verzeichnis, String ... packagesName) throws Exception {

MetadataSources metadata = new MetadataSources(
      new StandardServiceRegistryBuilder() 
        .applySetting("hibernate.dialect", dialect.getName()) 
        .build()); 

    for (String packageName : packagesName) { 
     LOG.info("packageName: " + packageName); 
     for (Class clazz : getClasses(packageName)) { 
      LOG.info("Class: " + clazz); 
      metadata.addAnnotatedClass(clazz); 
     } 
    } 

    MetadataImplementor metadataImplementor = (MetadataImplementor) metadata.buildMetadata(); 
    SchemaExport export = new SchemaExport(); 

    export.setDelimiter(";"); 
    String filename = directory + "ddl_" + dialect.getSimpleName().toLowerCase() + ".sql"; 
    export.setOutputFile(filename); 
    export.setFormat(true); 

    //can change the output here 
    EnumSet<TargetType> enumSet = EnumSet.of(TargetType.STDOUT); 
    export.execute(enumSet, SchemaExport.Action.CREATE, metadataImplementor); 
} 
Verwandte Themen