Grails 3.1.6,Hibernate 4.复合外键

时间:2016-12-02 08:19:36

标签: hibernate grails foreign-keys gorm composite-primary-key

class Tooth {
  Integer id
  ToothDisease toothDisease
   static mapping = {
    table name: 'AK_TOOTH'
    id generator: 'sequence', params: [sequence: 'SEQ_AK_TOOTH']
    columns{
        toothDisease {
        column: 'FK_AK_TOOTH_ID' 
        column: 'FK_AK_TOOTH_NR_VERSION' 
        }
    }
} 
class ToothDisease implements Serializable{
  Integer idColumn
  Integer nrVersion
   static mapping = {
    table name: 'AK_TOOTH_DISEASE'
    idColumn column: 'ID', generator: 'sequence', params: [sequence: 'SEQ_AK_TOOTH_DISEASE']
    nrVersion  column: 'NR_VERSION',
    id composite ['idColumn','nrVersion']

   int hashCode () {
    def builder = new HashCodeBuilder ()
    builder.append (idColumn)
    builder.append (nrVersion)
    builder.toHashCode ()
  }

  boolean equals (other) {
    if (other == null) {
      return false
    }
    def builder = new EqualsBuilder ()
    builder.append (idColumn, other.idColumn)
    builder.append (nrVersion, other.nrVersion)
    builder.isEquals ()
  }
} 

当我尝试bootRun我的应用程序时,我得到了BeanCreationException:

Caused by: org.hibernate.MappingException: Foreign key (FK_1rnajvolkf4rkav5w1hl0l9fk:AK_TOOTH [tooth_disease_id,FK_AK_TOOTH_ID,FK_AK_TOOTH_NR_VERSION,tooth_disease_id_column,tooth_disease_nr_version])) must have same number of columns as the referenced primary key (AK_TOOTH_DISEASE [ID,NR_VERSION]).

当我删除Tooth中的列映射部分时,我得到了相同的错误,没有那些列

[tooth_disease_id,tooth_disease_id_column,tooth_disease_nr_version].

是否可以像在hibernate中一样显式定义key列和referencedColumnName? 为什么有三列?特别是tooth_disease_id and tooth_disease_id_column columns同时。我试图使用'primaryKey'名称作为Tooth的复合主键,'id'简单作为id列,但是这样,我有同样的错误

Caused by: org.hibernate.MappingException: Foreign key (FK_1rnajvolkf4rkav5w1hl0l9fk:AK_TOOTH [tooth_disease_id,FK_AK_TOOTH_ID,FK_AK_TOOTH_NR_VERSION,tooth_disease_id_column,tooth_disease_nr_version])) must have same number of columns as the referenced primary key (AK_TOOTH_DISEASE [ID]).But there is only one referenced primary key.

不幸的是,我没有机会改变架构结构并避免使用复合键。

2 个答案:

答案 0 :(得分:0)

我认为错误是由你在Tooth的映射中声明FK to ToothDisease的方式引起的。

试试这个:

class Tooth {
   Integer id
   ToothDisease toothDisease

   static mapping = {
      table name: 'AK_TOOTH'
      id generator: 'sequence', params: [sequence: 'SEQ_AK_TOOTH']
      toothDisease {
          column name: 'FK_AK_TOOTH_ID' 
          column name: 'FK_AK_TOOTH_NR_VERSION' 
      }
   }

} 

class ToothDisease implements Serializable{
   Integer idColumn
   Integer nrVersion

   static mapping = {
       table name: 'AK_TOOTH_DISEASE'
       idColumn column: 'ID', generator: 'sequence', params: [sequence: 'SEQ_AK_TOOTH_DISEASE']
       nrVersion  column: 'NR_VERSION'
       id composite: ['idColumn','nrVersion']
   }

   int hashCode () {
       def builder = new HashCodeBuilder ()
       builder.append (idColumn)
       builder.append (nrVersion)
       builder.toHashCode ()
   }

    boolean equals (other) {
       if (other == null) {
          return false
       }
       def builder = new EqualsBuilder ()
       builder.append (idColumn, other.idColumn)
       builder.append (nrVersion, other.nrVersion)
       builder.isEquals ()
    }

} 

答案 1 :(得分:0)

我找到了here 来自Burt Beckwith的解决方法。 由于GrailsAnnotationConfiguration被HibernateMappingContextConfiguration.groovy取代,我在他的解决方案中做了一些更改:

class CompositeForeignKeyConfiguration extends HibernateMappingContextConfiguration {
  private static final long serialVersionUID = 1
  private static final String TOOTH_CLASS_NAME = 'com.project.TOOTH'
    private static final String TOOTH_ID_FK = 'FK_AK_TOOTH_ID'
  private static final String TOOTH_VERSION_FK = 'FK_AK_TOOTH_NR_VERSION'

  private boolean _alreadyProcessed

  @SuppressWarnings ("unchecked")
  @Override
  protected void secondPassCompile () throws MappingException {

    for (PersistentEntity pc : hibernateMappingContext.getPersistentEntities ()) {
      if (pc.name == TOOTH_CLASS_NAME) {
        pc.getAssociations ().each { Association mp ->
          if (mp.name == 'toothDisease') {
            PropertyConfig config = (PropertyConfig) mp.getMapping ().getMappedForm ()
            if (config.columns.size () == 1) {
              config.columns.clear ()
              final ColumnConfig fk1 = new ColumnConfig (name: TOOTH_ID_FK )
              final ColumnConfig fk2 = new ColumnConfig (name: TOOTH_VERSION_FK )
              config.columns << fk1
              config.columns << fk2
            }
          }
        }
      }

    }

    super.secondPassCompile ()
    if (_alreadyProcessed) {
      return
    }
    _alreadyProcessed = true
  }
}