java 是否可以在 Hibernate/JPA 中动态定义列名?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3617687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:40:18  来源:igfitidea点击:

Is it possible to dynamically define column names in Hibernate / JPA?

javahibernateormjpa

提问by emeraldjava

So i have this existing DB schema with a number of tables that i want to model with JPA/Hibernate. Each table has the same group of 30 additional columns ( to allow for runtime expansion of the number of fields recorded).

所以我有这个现有的数据库模式,其中包含许多我想用 JPA/Hibernate 建模的表。每个表都有相同的 30 个附加列组(以允许运行时扩展记录的字段数)。

CREATE TABLE XX
  (
    "ID"          VARCHAR2(100 BYTE) NOT NULL ENABLE,
    "USER_LABEL"      VARCHAR2(256 BYTE),
    "CREATION_DATE"   NUMBER(38,0) NOT NULL ENABLE,
    "ADD_STR_FIELD_0" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_0" NUMBER(38,0),
    "ADD_DBL_FIELD_0" NUMBER(38,0),
    "ADD_STR_FIELD_1" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_1" NUMBER(38,0),
    "ADD_DBL_FIELD_1" NUMBER(38,0),
    "ADD_STR_FIELD_2" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_2" NUMBER(38,0),
    "ADD_DBL_FIELD_2" NUMBER(38,0),
    "ADD_STR_FIELD_3" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_3" NUMBER(38,0),
    "ADD_DBL_FIELD_3" NUMBER(38,0),
    "ADD_STR_FIELD_4" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_4" NUMBER(38,0),
    "ADD_DBL_FIELD_4" NUMBER(38,0),
    "ADD_STR_FIELD_5" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_5" NUMBER(38,0),
    "ADD_DBL_FIELD_5" NUMBER(38,0),
    "ADD_STR_FIELD_6" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_6" NUMBER(38,0),
    "ADD_DBL_FIELD_6" NUMBER(38,0),
    "ADD_STR_FIELD_7" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_7" NUMBER(38,0),
    "ADD_DBL_FIELD_7" NUMBER(38,0),
    "ADD_STR_FIELD_8" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_8" NUMBER(38,0),
    "ADD_DBL_FIELD_8" NUMBER(38,0),
    "ADD_STR_FIELD_9" VARCHAR2(200 BYTE),
    "ADD_LNG_FIELD_9" NUMBER(38,0),
    "ADD_DBL_FIELD_9" NUMBER(38,0),
}

I plan to define simple classes for each table

我计划为每个表定义简单的类

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="XX")
public class XX {

    @Id
    Long id = null;
}

and then define the common additional parameters in a common class

然后在通用类中定义通用的附加参数

import javax.persistence.Column;

public abstract class AdditionalParameters {

    @Column(name="ADD_STR_FIELD_0")
    private String addStringField0 = null;
    @Column(name="ADD_LNG_FIELD_0")
    private Long addLongField0 = null;
    @Column(name="ADD_DBL_FIELD_0")
    private Double addDoubleField0 = null;
    ....
    ....
    ....
    @Column(name="ADD_STR_FIELD_8")
    private String addStringField8 = null;
    @Column(name="ADD_LNG_FIELD_8")
    private Long addLongField8 = null;
    @Column(name="ADD_DBL_FIELD_8")
    private Double addDoubleField8 = null;
}

while this will work, i don't like the hardcoded nature of the class.

虽然这会起作用,但我不喜欢类的硬编码性质。

I would like to model each set of string,long and double fields as an additional parameter group, and then have 0..9 groups. This would allow me easily add extra groups later if required.

我想将每组字符串、长字段和双字段建模为一个附加参数组,然后有 0..9 个组。如果需要,这将允许我稍后轻松添加额外的组。

If i use the xml mapping solution i can dynamically determine the correct column name when generating the .hbm.xml for each table. I would prefer to use an annotated solution, but is there a way to override the @Column getName() method so that i can return a dynamically generated column name?

如果我使用 xml 映射解决方案,我可以在为每个表生成 .hbm.xml 时动态确定正确的列名。我更喜欢使用带注释的解决方案,但是有没有办法覆盖 @Column getName() 方法,以便我可以返回动态生成的列名?

回答by Sean Patrick Floyd

You need to create a custom NamingStrategy.

您需要创建一个自定义NamingStrategy

Assuming you use spring and hibernate with JPA, here is a configuration snippet with a custom NamingStrategy:

假设您在 JPA 中使用 spring 和 hibernate,这里是一个带有自定义 NamingStrategy 的配置片段:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myunit" />
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceXmlLocation"
              value="classpath:META-INF/persistence.xml" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="false" />
            <property name="generateDdl" value="true" />
            <property name="database" value="MYSQL" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop 
                key="hibernate.ejb.naming_strategy">
                com.yourcompany.CustomNamingStrategy
            </prop>
        </props>
    </property>
</bean>

If you don't use spring, configuration will be different, but you can still use a custom NamingStrategy (see Implementing a NamingStrategyfrom the Hibernate Documentation).

如果您不使用 spring,配置会有所不同,但您仍然可以使用自定义 NamingStrategy(请参阅Hibernate 文档中的实现 NamingStrategy)。

Anyway, here is a sample NamingStrategy that builds table names of the form TYPE1_TYPE2 for join tables and adds a common prefix to all tables:

无论如何,这是一个示例 NamingStrategy,它为连接表构建 TYPE1_TYPE2 形式的表名,并为所有表添加一个公共前缀:

public class CustomNamingStrategy extends ImprovedNamingStrategy {

    private static final long serialVersionUID = 1L;
    private static final String PREFIX = "PFX_";

    @Override
    public String classToTableName(final String className) {
        return this.addPrefix(super.classToTableName(className));
    }

    @Override
    public String collectionTableName(final String ownerEntity,
            final String ownerEntityTable, final String associatedEntity,
            final String associatedEntityTable, final String propertyName) {
        return this.addPrefix(super.collectionTableName(ownerEntity,
                ownerEntityTable, associatedEntity, associatedEntityTable,
                propertyName));
    }

    @Override
    public String logicalCollectionTableName(final String tableName,
            final String ownerEntityTable, final String associatedEntityTable,
            final String propertyName) {
        return this.addPrefix(super.logicalCollectionTableName(tableName,
                ownerEntityTable, associatedEntityTable, propertyName));
    }

    private String addPrefix(final String composedTableName) {

        return PREFIX
                + composedTableName.toUpperCase().replace("_", "");

    }

}