web-dev-qa-db-fra.com

Où est passé Configuration.generateSchemaCreationScript () dans Hibernate 5

Dans Hibernate 4.x, j'avais l'habitude de générer et d'exporter le schéma tel que défini dans les entités annotées comme suit (en utilisant Spring pour trouver des entités annotées sur le chemin de classe):

Connection connection = 
    DriverManager.getConnection("jdbc:h2:mem:jooq-meta-extensions", "sa", "");

Configuration configuration = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

// [...] adding annotated classes to Configuration here...

configuration.generateSchemaCreationScript(
    Dialect.getDialect(configuration.getProperties()));
SchemaExport export = new SchemaExport(configuration, connection);
export.create(true, true);

Cela ne fonctionne plus dans Hibernate 5.0:

Je n'ai pas vraiment trouvé de références évidentes à ce changement dans le guide de migration à part:

De nombreuses méthodes ont été supprimées de la configuration

Quelle est la bonne façon de générer et d'exporter une base de données sur une connexion JDBC existante avec Hibernate 5.0 sur la base d'un ensemble d'entités annotées? (Les solutions basées sur JPA sont également très bien)

(Remarque, supprimer simplement l'appel à generateSchemaCreationScript() semble fonctionner, mais je préférerais être sûr de bien faire les choses)

28
Lukas Eder

Grâce aux réponses de Vlad et Gunnar , j'ai réussi à trouver mon chemin à travers la nouvelle API de configuration pour produire la logique d'exportation équivalente avec ce qui suit. Bien sûr, l'histoire montre que cette API se cassera à nouveau, alors assurez-vous de choisir la version appropriée:

Hibernate 5.2:

MetadataSources metadata = new MetadataSources(
    new StandardServiceRegistryBuilder()
        .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
        .applySetting("javax.persistence.schema-generation-connection", connection)
        .build());

// [...] adding annotated classes to metadata here...
metadata.addAnnotatedClass(...);

SchemaExport export = new SchemaExport();
export.create(EnumSet.of(TargetType.DATABASE), metadata.buildMetadata());

Hibernate 5.2 (sans avertissements):

Ce qui précède produira quelques avertissements désagréables, qui peuvent être ignorés:

20 oct. 2016 2:57:16 PM org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator InitierService
AVERTISSEMENT: HHH000181: Aucun fournisseur de connexion approprié rencontré, en supposant que l'application fournira des connexions
20 oct. 2016 2:57:16 PM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator initierService
AVERTISSEMENT: HHH000342: Impossible d'obtenir la connexion pour interroger les métadonnées: l'application doit fournir des connexions JDBC

... ou contournez-les en piratant le ConnectionProvider suivant dans les paramètres (cela ne devrait pas être obligatoire à mon avis)

        .applySetting(AvailableSettings.CONNECTION_PROVIDER, new ConnectionProvider() {
            @Override
            public boolean isUnwrappableAs(Class unwrapType) {
                return false;
            }
            @Override
            public <T> T unwrap(Class<T> unwrapType) {
                return null;
            }
            @Override
            public Connection getConnection() {
                return connection; // Interesting part here
            }
            @Override
            public void closeConnection(Connection conn) throws SQLException {}

            @Override
            public boolean supportsAggressiveRelease() {
                return true;
            }
        })

Hibernate 5.0:

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

// [...] adding annotated classes to metadata here...
metadata.addAnnotatedClass(...);

SchemaExport export = new SchemaExport(
    (MetadataImplementor) metadata.buildMetadata(),
    connection // pre-configured Connection here
);
export.create(true, true);

Hibernation 4:

Pour rappel, voici comment cela a fonctionné dans Hibernate 4:

Configuration configuration = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

// [...] adding annotated classes to metadata here...
configuration.addAnnotatedClass(...);

configuration.generateSchemaCreationScript(
    Dialect.getDialect(configuration.getProperties()));
SchemaExport export = new SchemaExport(configuration, connection);
export.create(true, true);
27
Lukas Eder

Un exemple de la nouvelle initialisation SchemaExport se trouve dans SchemaExportTask :

final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build();

final MetadataSources metadataSources = new MetadataSources( bsr );
final StandardServiceRegistryBuilder ssrBuilder = new StandardServiceRegistryBuilder( bsr );

if ( configurationFile != null ) {
    ssrBuilder.configure( configurationFile );
}
if ( propertiesFile != null ) {
    ssrBuilder.loadProperties( propertiesFile );
}
ssrBuilder.applySettings( getProject().getProperties() );

for ( String fileName : getFiles() ) {
    if ( fileName.endsWith(".jar") ) {
        metadataSources.addJar( new File( fileName ) );
    }
    else {
        metadataSources.addFile( fileName );
    }
}


final StandardServiceRegistryImpl ssr = (StandardServiceRegistryImpl) ssrBuilder.build();
final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder( ssr );

ClassLoaderService classLoaderService = bsr.getService( ClassLoaderService.class );
if ( implicitNamingStrategy != null ) {
    metadataBuilder.applyImplicitNamingStrategy(
            (ImplicitNamingStrategy) classLoaderService.classForName( implicitNamingStrategy ).newInstance()
    );
}
if ( physicalNamingStrategy != null ) {
    metadataBuilder.applyPhysicalNamingStrategy(
            (PhysicalNamingStrategy) classLoaderService.classForName( physicalNamingStrategy ).newInstance()
    );
}

return new SchemaExport( (MetadataImplementor) metadataBuilder.build() )
    .setHaltOnError( haltOnError )
    .setOutputFile( outputFile.getPath() )
    .setDelimiter( delimiter );

Bien sûr, vous pouvez le personnaliser selon vos besoins.

4
Vlad Mihalcea

La nouvelle API bootstrap permet de nombreuses personnalisations, mais en supposant que vous n'en ayez pas besoin, l'invocation la plus courte ressemblerait à cela, en appliquant les valeurs par défaut pour les registres de service et tous les paramètres:

Metadata metadata = new MetadataSources()
    .addAnnotatedClass( MyEntity.class )
    .build();

new SchemaExport( (MetadataImplementor) metadata )
    .setOutputFile( "my-statements.ddl" )
    .create( Target.NONE );

pdate: Fournir un exemple d'application des propriétés de configuration

Il existe plusieurs façons d'injecter des propriétés pour l'URL de connexion, le dialecte, etc. vous pouvez fournir un fichier hibernate.properties ou vous utilisez un registre de service personnalisé avec les paramètres requis:

StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
    .applySetting( "hibernate.connection.url", "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" )
    .build();

Metadata metadata = new MetadataSources( registry )
    .build();
3
Gunnar

Je l'ai exporté de cette façon avec hibernate 5.4.9.

import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;

import Java.util.EnumSet;

public class ExportSchema {
    public static void main(String[] args) {
        final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
                .build();
        final Metadata metadata = new MetadataSources(serviceRegistry)
                .addAnnotatedClass(...)
                .buildMetadata();
        new SchemaExport()
                .setFormat(true)
                .setDelimiter(";")
                .setOutputFile("schema.sql")
                .execute(EnumSet.of(TargetType.SCRIPT), SchemaExport.Action.CREATE, metadata);
    }
}
0
Kristof Neirynck

Dans le cas où l'on utilise JPA 2.1+ - il existe une possibilité de construction très simple pour générer le ddl. définissez simplement les propriétés jpa suivantes et les fichiers ddl seront créés. Avec Spring Boot, on pourrait écrire une classe principale séparée avec ces options de configuration spécifiques.

JPA 2.1 +

javax.persistence.schema-generation.scripts.action=drop-and-create
javax.persistence.schema-generation.scripts.create-target=create.ddl
javax.persistence.schema-generation.scripts.drop-target=drop.ddl

Spring Boot avec JPA 2.1 +

schemagenerator.properties (placé dans le dossier des ressources):

spring.jpa.properties.javax.persistence.schema-generation.scripts.action=drop-and-create
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.ddl
spring.jpa.properties.javax.persistence.schema-generation.scripts.drop-target=drop.ddl
flyway.enabled=false // in case you use flyway for db maintenance

Générateur de schéma Spring Boot:

public class SchemaGenerator {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, new String[]{"--spring.config.name=schemagenerator"}).close();
    }
}
0
fischermatte