#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;
}
Похоже, что принудительное применение ассоциации на уровне суперкласса делает свое дело. Я не знаю, является ли это чистым побочным эффектом или необходимостью проектирования. Я не нашел никаких ресурсов по этому вопросу.