如何使用带有BeanValidation约束的Hibernate SchemaExport导出数据库模式?

时间:2014-06-10 02:59:49

标签: java hibernate bean-validation

请参阅我的要求:使用SchemaExport导出已应用BeanValidation约束的数据库模式(例如,@ Length(32)将创建数据库约束:column(32))。

在Hibernate 4.1.x中,我可以在这里使用hack代码:https://forum.hibernate.org/viewtopic.php?f=1&t=1024911&view=previous

但是在Hibernate 4.3.5中删除了上述hack代码中所需的 Ejb3Configuration 类。

那么如何在不使用 Ejb3Configuration 的情况下导出应用BeanValidation约束的数据库模式?

2 个答案:

答案 0 :(得分:1)

这样的事情应该有效:

PersistenceUnitDescriptorAdapter pu = new PersistenceUnitDescriptorAdapter() {
    @Override
    public List<String> getManagedClassNames() {
        return Arrays.asList( MyClass.class.getName(), ... );
    }
};

Map<Object, Object> settings = new HashMap<Object, Object>();
settings.put( "javax.persistence.schema-generation.scripts.action", "create" );
settings.put( "javax.persistence.schema-generation.scripts.create-target", "<path-to-export-file>" );
EntityManagerFactoryBuilderImpl factoryBuilder = new EntityManagerFactoryBuilderImpl( pu, settings );
factoryBuilder.generateSchema();

它依赖于Hibernate内部类,但您的早期解决方案也是如此。你可以在这里创建一个问题 - https://hibernate.onjira.com/browse/HHH - 解释你的用例。也许可以使用公共API的解决方案。

答案 1 :(得分:0)

我通过EntityManagerFactoryBuilderImpl使用HibernationConfiguration构建找到了一个临时解决方案。它使用JPA配置发出模式脚本(使用bean验证器约束)。

public final class JpaSchemaExporter
{
    public JpaSchemaExporter(String utilName, String packageName, Properties properties, DialectType dialect,
                 Path outputPath) throws Exception
    {
        this.dialect = dialect;
        this.outputPath = outputPath;

        if (Files.exists(outputPath) && !Files.isDirectory(outputPath)) {
            throw new IllegalArgumentException(
                "Given path already exist and is not a directory! the path:" + outputPath);
        }
        Files.createDirectories(outputPath);

        pud = new ParsedPersistenceXmlDescriptor(Resources.getResourceURL("META-INF"));
        pud.setName(utilName);
        pud.addClasses(Resources.getClasseNames(packageName));
        pud.addMappingFiles("META-INF/orm.xml");
        properties.setProperty("hibernate.dialect", dialect.getDialectClass());

        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        factoryBuilder = new EntityManagerFactoryBuilderImpl( pud, properties );
        factoryBuilder.withValidatorFactory(validatorFactory).build().close(); // create HibernateConfiguration instance
        this.injectBeanValidationConstraintToDdlTranslator();
        validatorFactory.close();
    }

    private void injectBeanValidationConstraintToDdlTranslator() {
        try {
            Configuration hibernateConfiguration = factoryBuilder.getHibernateConfiguration();
            ValidatorFactory validatorFactory = (ValidatorFactory) factoryBuilder.getConfigurationValues().get(AvailableSettings.VALIDATION_FACTORY);
            // private class in hibernate
            Method applyRelationalConstraints = Class.forName("org.hibernate.cfg.beanvalidation.TypeSafeActivator")
                .getMethod("applyRelationalConstraints",
                       ValidatorFactory.class,
                       java.util.Collection.class,
                       Properties.class,
                       Dialect.class);
            applyRelationalConstraints.setAccessible(true);
            Dialect dialectInstance = (Dialect) Class.forName(dialect.getDialectClass()).newInstance();
            applyRelationalConstraints.invoke(null, validatorFactory,
                              Arrays.asList(Iterators.toArray(hibernateConfiguration.getClassMappings(), PersistentClass.class)) ,
                              hibernateConfiguration.getProperties(),
                              dialectInstance);
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public void create() throws IOException {
        Configuration cfg = factoryBuilder.getHibernateConfiguration();
        cfg.setProperty("hibernate.hbm2ddl.auto", "create");
        SchemaExport export = new SchemaExport(cfg);
        export.setDelimiter(";");
        export.setOutputFile(Paths.get(outputPath.toString(), "ddl_create_" + dialect.name().toLowerCase() + ".sql").toString());
        export.execute(true, false, false, true);
        if (!export.getExceptions().isEmpty()) {
            System.out.println();
            System.out.println("SOME EXCEPTIONS OCCURED WHILE GENERATING THE UPDATE SCRIPT:");
            for (Exception e : (List<Exception>) export.getExceptions()) {
            System.out.println(e.getMessage());
            }
        }
    }

    @SuppressWarnings("unchecked")
    public void update() throws IOException {
        Configuration cfg = factoryBuilder.getHibernateConfiguration();
        cfg.setProperty("hibernate.hbm2ddl.auto", "update");
        SchemaUpdate updater = new SchemaUpdate(cfg);
        updater.setDelimiter(";");
        updater.setOutputFile(Paths.get(outputPath.toString(), "ddl_update_" + dialect.name().toLowerCase() + ".sql").toString());
        updater.execute(true, false);
        if (!updater.getExceptions().isEmpty()) {
            System.out.println();
            System.out.println("SOME EXCEPTIONS OCCURED WHILE GENERATING THE UPDATE SCRIPT:");
            for (Exception e : ((List<Exception>) updater.getExceptions())) {
            System.out.println(e.getMessage());
            }
        }
    }

    public void validate() {
        Configuration hibernateConfiguration = factoryBuilder.getHibernateConfiguration();
        hibernateConfiguration.setProperty("hibernate.hbm2ddl.auto", "validate");
        SchemaValidator validator = new SchemaValidator(hibernateConfiguration);
        validator.validate();
    }

    public static void main(String[] args) throws Exception {
        Properties prop = new Properties(System.getProperties());
        prop.setProperty("hibernate.connection.driver_class", "value in your env");
        prop.setProperty("hibernate.connection.url", "value in your env");
        prop.setProperty("hibernate.connection.username", "value in your env");
        prop.setProperty("hibernate.connection.password", "value in your env");
        Path path = Paths.get("schema output path in your env");
        String packageName = prop.getProperty("package names of jpa classes");
        String unitName = prop.getProperty("jpa Unit Name");
        String[] dialects = "HSQL,MYSQL".split(",");
        for(String dialect : dialects){
            DialectType dialectType = DialectType.valueOf(dialect);
            JpaSchemaExporter ddlExporter = new JpaSchemaExporter(unitName, packageName, prop, dialectType, path);
            ddlExporter.update();
            ddlExporter.create();
        }
    }
}