在将 Map 和 @ElementCollection 与休眠一起使用时指定外键约束名称

2022-09-02 14:07:22

我有一个字段的奇异映射:

@ElementCollection
@CollectionTable(name = "studentGradeLevel", joinColumns = @JoinColumn(name = "studentId"))
@MapKeyJoinColumn(name = "schoolYearId")
@Column(name = "gradeLevel", nullable = false)
@ForeignKey(name = "fkStudentGrade2Student")
private Map<SchoolYear, GradeLevel> gradeLevels;

SchoolYear是一个实体,GradeLevel是一个枚举。

我正在使用休眠工具为架构生成DDL。生成的架构如下:

create table studentGradeLevel (
    studentId numeric(19,0) not null,
    gradeLevel int not null,
    schoolYearId int not null,
    primary key (studentId, schoolYearId)
);

alter table studentGradeLevel 
    add constraint FK1BCA4A883A97C498 
    foreign key (schoolYearId) 
    references schoolYear;

alter table studentGradeLevel 
    add constraint fkStudentGrade2Student 
    foreign key (studentId) 
    references student;

问题是,我似乎无法更改集合表和用作映射键的实体的表之间的外键的约束名称。

我使用@ForeignKey为@OneToMany,@ManyToMany和其他@ElementCollections指定约束名称,没有问题。我尝试过@ForiegnKey的“inverseName”属性,但它似乎被忽略了。@MapKeyJoinColumn似乎没有任何会影响此属性。

有谁知道是否有办法做到这一点?


答案 1

我不得不修补Hibernate以创建不同的外键名称,因为Hibernate为我创建的那些并不是很有用。

我获取了Hibernate源代码,并将类的Source放入我的source文件夹中,这是类路径的开始(我的项目中生成的jar以低于hibernate的字母开头.jar,因此这甚至适用于webapps)。org.hibernate.mapping.Table

I 将函数 uniqueColumnString 替换为以下代码(函数顶部的原始代码):

    public String uniqueColumnString(Iterator iterator, String referencedEntityName) {
//        int result = 0;
//        if ( referencedEntityName != null ) {
//            result += referencedEntityName.hashCode();
//        }
//        while ( iterator.hasNext() ) {
//            result += iterator.next().hashCode();
//        }
//        return ( Integer.toHexString( name.hashCode() ) + Integer.toHexString( result ) ).toUpperCase();
          StringBuilder retVal = new StringBuilder();
          retVal.append("_").append(referencedEntityName);
          while( iterator.hasNext() ) {
              Column c = (Column)iterator.next();
              retVal.append("_");
              retVal.append(c.getName());
          }
          return retVal.toString();
    }

这会自动返回像“_Entity_attributeName_id”这样的漂亮字符串,这些字符串将用于创建像“fk_Entity_attributeName_id”这样的外键!永远不必再次手动指定我的名字:)))


答案 2

我遇到了同样的问题,因为我找不到一种方法来做到这一点,最终查询数据库本身以获取该信息。

在 SQL SERVER 上运行此查询

select kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, tc.CONSTRAINT_TYPE, kcu.COLUMN_NAME
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
join INFORMATION_SCHEMA.KEY_COLUMN_USAGE as kcu
on kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
and kcu.CONSTRAINT_NAME  = tc.CONSTRAINT_NAME
and kcu.TABLE_SCHEMA    = tc.TABLE_SCHEMA
and kcu.TABLE_NAME = tc.TABLE_NAME

您将获得表名,约束名称(如FK1BCA4A883A97C498),类型(如UNIQUE约束)和列名。这应该足以返回有意义的错误消息。

我知道这不是很好,因为你失去了数据库的可移植性,但显然目前没有办法做你所要求的......


推荐