【问题标题】:Hiberante 4.3.6 DDL generation: Uppercase names for columns included in indexesHibernate 4.3.6 DDL 生成:索引中包含的列的大写名称
【发布时间】:2014-09-21 23:20:47
【问题描述】:

我有一些关于索引和约束名称区分大小写的问题 在hibernate生成的数据库模式中。 我的目的是让它们大写,但是 我无法实现它

这些是系统库/组件的主要功能:

  • 针对 PostgreSQL 9.3 数据库休眠 4.3.6。
  • 我正在为实体使用注释并尝试使用以下句子生成架构:

    Persistence.createEntityManagerFactory("vegaUnitDDL").createEntityManager();

接下来是我用来尝试不同选项的测试实体:

package net.test.software.test001.persistence.jpa;

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

@Entity
@Table(name="\"V_TEST\""
   , catalog="\"VEGA_DB_SCHEMA\""
   , indexes = {@Index(name="V_TEST_IDX", columnList="`TYPE`")}
)
public class Test {

  @Column(name="\"TEST_ID\"")
  @Id
  private long id = 0;

  @Column(name="\"TYPE\"", nullable=false)
  private String type = null;

}

persistene.xml 是:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.co/xml/ns/persistence/persistence_2_0.xsd"
         version="2.0">
  <persistence-unit name="vegaUnitDDL" transaction-type="RESOURCE_LOCAL">
      <!-- -->
      <class>net.test.software.test001.persistence.jpa.Test</class>
      <!-- -->
      <properties>
          <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
          <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/VEGA_DB"/>
          <property name="javax.persistence.jdbc.user" value="VEGA_USER"/>
          <property name="javax.persistence.jdbc.password" value="password"/>
          <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect"/>
          <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
          <property name="hibernate.show_sql" value="true" />
          <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      </properties>
  </persistence-unit>
</persistence>        

启动模式生成的主类:

package net.test.software.test001.persistence.jpa.model;

import javax.persistence.Persistence;

public class SchemaGenerator {
    public SchemaGenerator() {
        System.out.println("Creating the entity manager factory.");
        Persistence.createEntityManagerFactory("vegaUnitDDL").createEntityManager();
        System.out.println("DB schema created.");
    }

    public static void main(String[] args) {
        try {
            new SchemaGenerator();
            System.out.print("+-*.:+-*.:+-*.:+-*.:+-*.:");
            System.exit(0);
        } catch(Exception ex) {
            ex.printStackTrace();
            System.err.print(">>>>>>>>>>>>>>>>>>>>>>>>>");
            System.exit(-1);
        }
    }
}

最后是表的ddl和pgAdmin工具返回的索引(一旦在数据库中创建了模式):

-- Table: "VEGA_DB_SCHEMA"."V_TEST"

-- DROP TABLE "VEGA_DB_SCHEMA"."V_TEST";

CREATE TABLE "VEGA_DB_SCHEMA"."V_TEST"
(
   "TEST_ID" bigint NOT NULL,
   "TYPE" character varying(255) NOT NULL,
   CONSTRAINT "V_TEST_pkey" PRIMARY KEY ("TEST_ID")
)
WITH (
    OIDS=FALSE
);

ALTER TABLE "VEGA_DB_SCHEMA"."V_TEST"
OWNER TO "VEGA_SYS";

-- Index: "VEGA_DB_SCHEMA".v_test_type_idx

-- DROP INDEX "VEGA_DB_SCHEMA".v_test_type_idx;

CREATE INDEX v_test_type_idx
  ON "VEGA_DB_SCHEMA"."V_TEST"
USING btree
  ("TYPE" COLLATE pg_catalog."default");

问题:

1.- 我怎样才能让 V_TEST_pkey 完全大写?我可以使用 persistence.xml 文件中的任何属性吗?

2.- 我必须在反引号之间为@Index 编写columnList 参数中的列吗?它们不应该在双引号之间吗? (即 columnList="\"TYPE\"" 而不是 columnList="`TYPE`")

如果我想让hibernate创建大写,那么@Column注解中的TYPE列必须双引号。这就是我在 Test 类中声明它的方式。然而,关于@Index 注释,如果我使用“TYPE”而不是“TYPE”,它会失败。

我不得不进行一些调试以了解 hibernate 是如何管理它的。

A) 首先,让我们看看 hibernate 解析任何列信息的方式:在这个过程中,它在列的逻辑名称、用于内部引用的名称和它的物理名称之间构建了一个映射。 name,创建表时在 DDL 中声明的名称。它还使物理名称到逻辑名称的反向映射。逻辑名称仅供库内部使用,取决于休眠命名策略。为了得到它,hibernates通过一系列操作处理java注解@Column中指示的名称:

它开始把双引号变成反引号(\"TEST_ID\" -> `TEST_ID`; \"TYPE\" -> `TYPE`)

final String columnName = nameNormalizer.normalizeIdentifierQuoting( col.name() );

在后面的步骤中,当它获得逻辑-物理映射时,它使用命名策略来查看它必须为逻辑名称取的字符串:

String logicalColumnName = mappings.getNamingStrategy().logicalColumnName(this.logicalColumnName, propertyName );

你可以在 Configure 类中看到后面的语句,它被称为列绑定:

protected void addColumnBinding(SimpleValue value) {
    String logicalColumnName = mappings.getNamingStrategy()
        .logicalColumnName( this.logicalColumnName, propertyName );
    mappings.addColumnBinding( logicalColumnName, getMappingColumn(), value.getTable());
}

在我们的例子中,只是使用之前在 persistence.xml 文件中显示的配置,为列 TEST_ID 和 TYPE 返回的名称与作为参数传递给 logicalColumnName 方法的值相同,即 `TEST_ID`、`TYPE `。

为了保存物理列和逻辑列之间的引用,hibernate把它们放在哈希表中:见Configuration类的内部类MappingsImp的方法bindLogicalToPhysical。它用于逻辑名称的键是我们传递给它的全部变成小写的键(`TEST_ID` -> `test_id`; `TYPE` -> `type`):

private void bindLogicalToPhysical(String logicalName, Column physicalColumn) throws DuplicateMappingException {
    final String logicalKey = logicalName.toLowerCase();
    final String physicalName = physicalColumn.getQuotedName();
    final String existingPhysicalName = ( String ) logicalToPhysical.put( logicalKey, physicalName );
    ...
}

B)现在让我们看看hibernate如何管理@Index中指示的列:

假设它必须取columnList中的列名,并得到它的逻辑名。然后它将通过之前在列信息解析中完成的映射获取物理名称。只是,当获取逻辑名称时,hibernate 似乎是不同的。

它采用@Index 注释中写的名称,但它不应用“标识符引用规范化”,因此它不会更改反引号的双引号。然后在地图中搜索时,它使用名称的小写转换作为键,就像创建映射时一样。因此,我们必须在 columList 中使用 `TYPE` 而不是 \"TYPE\"。 这是一个错误吗?在我看来,将您在@Column 中为@Index 的 columnList 参数编写的相同字符串更有意义。

当名称为小写时,所有这些问题都解决了:Hibernate: Create Index

【问题讨论】:

标签: java hibernate jpa jpa-2.0


【解决方案1】:
猜你喜欢
  • 1970-01-01
  • 2020-02-03
  • 2016-04-29
  • 1970-01-01
  • 2012-08-23
  • 2017-02-09
  • 1970-01-01
  • 2019-09-03
  • 2012-01-18
相关资源
最近更新 更多