【问题标题】:How to discover fully qualified table column from Hibernate MetadataSources如何从 Hibernate MetadataSources 中发现完全限定的表列
【发布时间】:2018-02-01 06:20:39
【问题描述】:

我有一个实体,我有一个 Class<MyEntity> 参考:

@Entity
class MyEntity {
    @Id int id;
    @Column String col1;
    @Column(name = "abc") String col2;
}

我目前正在使用 Hibernate 将我的实体导出到内存数据库中:

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

Details about the Hibernate-specific API here.

有没有可靠的方法通过 Hibernate API 获取从 MyEntity.col2(带注释的 Java 字段引用)到数据库中完全限定的列名(反之亦然)的映射?在没有明确限定的情况下,我想避免重新实现 Java 标识符(包括 getter 和 setter)如何映射到 SQL 标识符的所有微妙细节。

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    org.hibernate.boot.Metadata 是我们感兴趣的,因为它包含 PersistentClass 实体绑定。

    首先,您需要创建一个Integrator,它可以让您访问Metadata

    public class MetadataExtractorIntegrator 
        implements org.hibernate.integrator.spi.Integrator {
     
        public static final MetadataExtractorIntegrator INSTANCE = 
            new MetadataExtractorIntegrator();
     
        private Database database;
     
        private Metadata metadata;
     
        public Database getDatabase() {
            return database;
        }
     
        public Metadata getMetadata() {
            return metadata;
        }
     
        @Override
        public void integrate(
                Metadata metadata,
                SessionFactoryImplementor sessionFactory,
                SessionFactoryServiceRegistry serviceRegistry) {
     
            this.database = metadata.getDatabase();
            this.metadata = metadata;
     
        }
     
        @Override
        public void disintegrate(
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {
     
        }
    }
    

    如果你使用JPA,可以如下注册:

    Map<String, Object> configuration = new HashMap<>();
     
    Integrator integrator = integrator();
    if (integrator != null) {
        configuration.put("hibernate.integrator_provider", 
            (IntegratorProvider) () -> Collections.singletonList(
                MetadataExtractorIntegrator.INSTANCE
            )
        );
    }
     
    EntityManagerFactory entityManagerFactory = new EntityManagerFactoryBuilderImpl(
        new PersistenceUnitInfoDescriptor(persistenceUnitInfo), 
        configuration
    )
    .build();
    

    现在,在运行以下测试用例时:

    Metadata metadata = MetadataExtractorIntegrator.INSTANCE.getMetadata();
    
    for ( PersistentClass persistentClass : metadata.getEntityBindings()) {
     
        Table table = persistentClass.getTable();
         
        LOGGER.info( "Entity: {} is mapped to table: {}",
                     persistentClass.getClassName(),
                     table.getName()
        );
     
        for(Iterator propertyIterator = persistentClass.getPropertyIterator(); 
                propertyIterator.hasNext(); ) {
            Property property = (Property) propertyIterator.next();
             
            for(Iterator columnIterator = property.getColumnIterator(); 
                    columnIterator.hasNext(); ) {
                Column column = (Column) columnIterator.next();
                 
                LOGGER.info( "Property: {} is mapped on table column: {} of type: {}",
                             property.getName(),
                             column.getName(),
                             column.getSqlType()
                );
            }
        }
    }
    

    针对以下实体:

    我们得到以下输出:

    Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$Tag is mapped to table: tag
    Property: name is mapped on table column: name of type: varchar(255)
    Property: version is mapped on table column: version of type: integer
     
    Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$PostComment is mapped to table: post_comment
    Property: post is mapped on table column: post_id of type: bigint
    Property: review is mapped on table column: review of type: varchar(255)
    Property: version is mapped on table column: version of type: integer
     
    Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$Post is mapped to table: post
    Property: title is mapped on table column: title of type: varchar(255)
    Property: version is mapped on table column: version of type: integer
     
    Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$PostDetails is mapped to table: post_details
    Property: createdBy is mapped on table column: created_by of type: varchar(255)
    Property: createdOn is mapped on table column: created_on of type: datetime(6)
    Property: version is mapped on table column: version of type: integer
    

    很酷,对吧?

    您也可以查看此示例 on GitHub

    【讨论】:

    • 嘿,这在带有 postgresql 的 Hibernate 5.4 中无法正常工作。除非您在属性中设置了 hibernate.hbm2ddl.auto=create,否则类型将返回为 null。我们希望使用validate,但是这样我们就无法访问属性类型。您知道这是否是预期行为,是否有解决方法?
    • hbm2ddl 设置不应影响Metadata 绑定。对我来说听起来像是一个错误。如果是这种情况,您需要复制它并打开 Hibernate Jira 问题。
    • 在我使用 SQL Server 的情况下,column.getSqlType() 将始终返回 null。但是,如果我们指定column.getSqlType(metadata.getDatabase().getDialect(), metadata),则返回正确的 sql 类型。
    猜你喜欢
    • 2018-06-21
    • 1970-01-01
    • 2018-07-19
    • 1970-01-01
    • 2015-04-03
    • 2017-12-25
    • 2013-11-21
    • 2015-08-03
    • 2020-10-25
    相关资源
    最近更新 更多