сопоставление суперкласса «таблица на иерархию классов», имеющего подклассы, отображающие подклассы другой «таблицы на иерархию классов»

#java #spring #hibernate #jpa #inheritance

#java #весна #спящий режим #jpa #наследование

Вопрос:

Извините за длинный заголовок..

При запросе объекта у меня возникает следующая ошибка TableColumn :

Не удалось установить значение поля [org.comp.domain.data.ConstantParameterType@18c81fe5] значение путем отражения : [class org.comp.data.AnalogParameter.analogParameterType] установщик org.comp.data.AnalogParameter.analogParameterType; вложенным исключением является org.hibernate.Исключение PropertyAccessException: не удалось установить значение поля [org.comp.data.Значение ConstantParameterType@18c81fe5] путем отражения : [class org.comp.domain.data.AnalogParameter.analogParameterType] установщик org.comp.domain.data.AnalogParameter.analogParameterType

Моя модель содержит две различные иерархии «одна таблица на класс», имеющие Parameter и ParameterType как суперклассы. Каждый подкласс Parameter иерархии сопоставляется с подклассом ParameterType иерархии посредством @ManyToOne ассоциаций. Вот выдержка из моей модели с задействованными объектами (пропущены несвязанные поля):

 // `Parameter` Single Table Per Class hierarchy

@Entity
@Table(name="parameters")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "category", discriminatorType = DiscriminatorType.STRING)

@DiscriminatorOptions(force=true)
public abstract class Parameter {

}

@Entity
@DiscriminatorValue(value="analog")
public class AnalogParameter extends Parameter {

    @ManyToOne
    @JoinColumn(name="parameter_type_id")
    private AnalogParameterType analogParameterType;

    public AnalogParameterType getAnalogParameterType() {
        return analogParameterType;
    }

    public void setAnalogParameterType(AnalogParameterType analogParameterType) {
        this.analogParameterType = analogParameterType;
    }


}

@Entity
@DiscriminatorValue(value="constant")
public class ConstantParameter extends Parameter {

    @ManyToOne
    @JoinColumn(name="parameter_type_id")
    private ConstantParameterType constantParameterType;

    public ConstantParameterType getConstantParameterType() {
        return constantParameterType;
    }

    public void setConstantParameterType(ConstantParameterType constantParameterType) {
        this.constantParameterType = constantParameterType;
    }

}

// `ParameterType` Single Table Per Class hierarchy

@Entity
@Table(name="parameters_types")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "category", discriminatorType = DiscriminatorType.STRING)

@DiscriminatorOptions(force=true)
public abstract class ParameterType { }

@Entity
@DiscriminatorValue(value="analog")
public class AnalogParameterType extends ParameterType { }

@Entity
@DiscriminatorValue(value="constant")
public class ConstantParameterType extends ParameterType {

}
  

Вот столбец таблицы, который сопоставляется с параметром superclass через ассоциацию @ManyToOne:

 @Entity
@Table(name="tables_columns")
public class TableColumn {

    @ManyToOne
    @JoinColumn(name="parameter_id")
    private Parameter parameter;

    public Parameter getParameter() {
        return parameter;
    }
}
  

И вот сгенерированный SQL при запросе объекта TableColumn:

выберите tablecolum0_.id как id1_12_0_, tablecolum0_.created_at как created_2_12_0_, tablecolum0_.is_optional как is_optio3_12_0_, tablecolum0_.parameter_id как paramete6_12_0_, tablecolum0_.position как position4_12_0_, tablecolum0_.updated_at как updated_5_12_0_, parameter1_.id как id2_8_1_, parameter1_.category как category1_8_1_, parameter1_.created_at как created_3_8_1_, parameter1_.device_id как device_14_8_1_, параметр1_.effective_date как effectiv4_8_1_, параметр1_.expiry_date как expiry_d5_8_1_, параметр1_.fqn как fqn6_8_1_, параметр1_.height_from_the_ground как height_f7_8_1_, параметр1_.label как метка8_8_1_, parameter1_.name как имя9_8_1_, параметр1_.разрешение_метка как разрешение10_8_1_, параметр1_.обновленный_ат как обновленный11_8_1_, параметр1_.параметр_типе_ид как параметр15_8_1_, параметр1_.значение_данных как дата_ва12_8_1_, параметр1_.разрешение как resolut13_8_1_, device2_.id как id1_1_2_, device2_.created_at как created_2_1_2_, device2_.device_type_id как device_t8_1_2_, device2_.fqn как fqn3_1_2_, device2_.label как label4_1_2_, device2_.name как name5_1_2_, device2_.примечания как notes6_1_2_, device2_.parent_device_id как parent_d9_1_2_, device2_.plant_id как plant_i10_1_2_, device2_.updated_at как updated_7_1_2_, constantpa3_.id как id2_9_3_, constantpa3_.created_at как created_3_9_3_, constantpa3_.description как descript4_9_3_, constantpa3_.is_signed как is_signe5_9_3_, constantpa3_.label как label6_9_3_, constantpa3_.name как name7_9_3_, constantpa3_.updated_at как updated_8_9_3_ из таблицы_колонки таблица0_ параметры внешнего соединения слева параметр1_ наtablecolum0_.parameter_id=parameter1_.id левое внешнее соединение устройств device2_ включено parameter1_.device_id=device2_.id параметры внешнего соединения слева_типируют константуpa3_ вкл . parameter1_.parameter_type_id=constantpa3_.id где tablecolum0_.id=1

Я использую Hibernate 5.0.11 с MySQL в проекте Spring Boot 1.4.1 / Data Rest

Редактировать

Я попробовал в проекте vanilla Maven / Hibernate, используя ту же базу данных. У меня та же ошибка. Если я запрашиваю Parameter объекты напрямую, все в порядке, но я получаю сообщение об ошибке, если я запрашиваю TableColumn :

     EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    // The following works
    List<Parameter> ps = entityManager.createQuery("from Parameter", Parameter.class).getResultList();
    for (Parameter p: ps) {
        System.out.println(p);
    }

    // But if i replace with following, i get the same error as reported
    // in the beginning of this question
    List<TableColumn> tcs = entityManager.createQuery("from TableColumn", TableColumn.class).getResultList();
    for (TableColumn tc: tcs) {
        System.out.println(tc);
    }


    entityManager.getTransaction().commit();
    entityManager.close();
  

Комментарии:

1. глядя на ваше отображение, я не вижу @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

2. к сожалению, это не устраняет проблему. Как указано в ассоциации JPA @inheritance в Hibernate javadoc , это тип по умолчанию, если он не указан

3. спасибо за информацию. Я этого не знал.

Ответ №1:

1) Ваш category из size=7 , но вы устанавливаете значение 8 characters , т.е., constant

 @DiscriminatorColumn(name="category", length=7)//change to more than 7
  

Потому что, @DiscriminatorValue(value="constant")//here the length is 8

Вы можете использовать приведенный ниже код для столбца дискриминатора:

 @DiscriminatorColumn(name = "category", discriminatorType = DiscriminatorType.STRING)//no need of length attribute
  

2) убедитесь, что для свойства private AnalogParameterType analogParameterType; , которое у вас есть, указаны методы setter и getter.

 //setter    
public void setAnalogParameterType(AnalogParameterType analogParameterType) {
    this.analogParameterType = analogParameterType;
}
//getter
public AnalogParameterType getAnalogParameterType() {
    return analogParameterType;
}
  

3) Вместо
@ManyToOne
@JoinColumn(name="parameter_type_id")

используйте @ManyToOne(cascade=CascadeType.ALL) для получения.
Например:

 @ManyToOne(cascade = CascadeType.ALL)
public AnalogParameterType getAnalogParameterType() {
    return analogParameterType;
}
  

Комментарии:

1. Это хороший улов, но, к сожалению, он не решает мою проблему. Я отредактировал вопрос, заменив @DiscriminatorColumn вашим предложением. Спасибо

2. Средства доступа есть. Я добавил их в вопрос (путем копирования вставки из реального кода)

3. о 3): я попробовал и дал> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Неизвестный столбец ‘parameter0_.constantParameterType_id’ в ‘списке полей’

4. (не могу отредактировать мой предыдущий пост?)… Он ищет несуществующий столбец ассоциации..

Ответ №2:

Итак, я решил свою проблему, сопоставив два суперкласса Parameter и ParameterType используя insertable / updatable= false:

 @Entity
@Table(name="parameters")
@DiscriminatorColumn(name = "category", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorOptions(force=true)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public abstract class Parameter {

    @ManyToOne
    @JoinColumn(name="parameter_type_id", insertable = false, updatable = false)
    private ParameterType parameterType;

}
  

Похоже, что принудительное применение ассоциации на уровне суперкласса делает свое дело. Я не знаю, является ли это чистым побочным эффектом или необходимостью проектирования. Я не нашел никаких ресурсов по этому вопросу.