开发者

Specify foreign key constraint name when using Map and @ElementCollection with Hibernate

I have a sort of exotic map开发者_运维知识库ping for a field:

@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 is an entity and GradeLevel is an enum.

I am using Hibernate tools to generate the DDL for the schema. The schema that this generates is below:

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;

The problem is that I can't seem to change the constraint name for the foreign key between the collection table and the table for the entity used as the map key.

I've used @ForeignKey to specify constraint names for @OneToMany, @ManyToMany and other @ElementCollections with no problem. I've tried @ForiegnKey's "inverseName" attribute but it seems to be ignored. @MapKeyJoinColumn doesn't appear to have any properties that would affect this.

Does anyone know if there is a way to do this?


I had to patch Hibernate to create different foreign key names, because the ones Hibernate created for me weren't really useful.

I took the Hibernate source, and placed the Source of the class org.hibernate.mapping.Table into my source folder, which is a the start of the classpath (the resulting jar in my project starts with a letter lower than the hibernate.jar, so this even works in webapps).

The I replaced the function uniqueColumnString with the following code (Original code at the top of the function):

    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();
    }

This returns automatically nice strings like "_Entity_attributeName_id", which will be used to create foreign keys like "fk_Entity_attributeName_id"! Never have to specify my names by hand again :)))


I had the same problem and because I couldn't find a way to do it ended up querying the database itself to get that information.

Running this query on 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

You will get tablename, constraint name (like FK1BCA4A883A97C498), type (like UNIQUE constraint) and column name. That should be enought to return a meaningful error message.

I know is not great because you loose the db portability but apparently there is no way to do what you are asking for at the moment...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜