map“table per class hierarchy”超类,其子类映射另一个“每个类层次结构的表”的子类

时间:2016-10-13 09:39:25

标签: java spring hibernate jpa inheritance

很抱歉长标题..

查询TableColumn实体时出现以下错误:

  

无法设置字段值   [org.comp.domain.data.ConstantParameterType@18c81fe5]值   反射:[class org.comp.data.AnalogParameter.analogParameterType]   org.comp.data.AnalogParameter.analogParameterType的setter;嵌套   异常是org.hibernate.PropertyAccessException:无法设置   字段值[org.comp.data.ConstantParameterType@18c81fe5]的值   反思:[班级   org.comp.domain.data.AnalogParameter.analogParameterType] setter of   org.comp.domain.data.AnalogParameter.analogParameterType

我的模型包含两个区别'每个类的单个表'层次结构,其中ParameterParameterType为超类。 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 {

}

这是通过@ManyToOne关联与Parameter超类映射的TableColumn:

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

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

    public Parameter getParameter() {
        return parameter;
    }
}

这是查询TableColumn实体时生成的SQL:

  

选择tablecolum0_.id为id1_12_0_,tablecolum0_.created_at为   created_2_12_0_,tablecolum0_.is_optional as is_optio3_12_0_,   tablecolum0_.parameter_id as paramete6_12_0_,tablecolum0_.position as   position4_12_0_,tablecolum0_.updated_at as updated_5_12_0_,   parameter1_.id为id2_8_1_,parameter1_.category为category1_8_1_,   parameter1_.created_at as created_3_8_1_,parameter1_.device_id as   device_14_8_1_,parameter1_.effective_date as effectiv4_8_1_,   parameter1_.expiry_date为expiry_d5_8_1_,parameter1_.fqn为   fqn6_8_1_,parameter1_.height_from_the_ground为height_f7_8_1_,   parameter1_.label为label8_8_1_,parameter1_.name为name9_8_1_,   parameter1_.resolution_label as resolut10_8_1_,parameter1_.updated_at   as updated11_8_1_,parameter1_.parameter_type_id as paramet15_8_1_,   parameter1_.data_validity_period as data_va12_8_1_,   parameter1_.resolution为resolut13_8_1_,device2_.id为id1_1_2_,   device2_.created_at as created_2_1_2_,device2_.device_type_id as   device_t8_1_2_,device2_.fqn为fqn3_1_2_,device2_.label为   label4_1_2_,device2_.name为name5_1_2_,device2_.notes为   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   as created_3_9_3_,constantpa3_.description as descript4_9_3_,   constantpa3_.is_signed as is_signe5_9_3_,constantpa3_.label as   label6_9_3_,constantpa3_.name as name7_9_3_,constantpa3_.updated_at   as_news_8_9_3_ from tables_columns tablecolum0_ left outer join   tablecolum0_.parameter_id = parameter1_.id上的参数parameter1_   左外连接设备device2_ on parameter1_.device_id = device2_.id   left outer join parameters_types constantpa3_ on   parameter1_.parameter_type_id = constantpa3_.id其中tablecolum0_.id = 1

我在Spring Boot 1.4.1 / Data Rest项目中使用Hibernate 5.0.11和MySQL

修改

我在一个使用相同数据库的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();

2 个答案:

答案 0 :(得分:0)

1)您的category属于size=7,但您设置的值为8 charactersconstant

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

因为,@DiscriminatorValue(value="constant")//here the length is 8

您可以将以下代码用于Discriminator列:

@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")

getters 上使用@ManyToOne(cascade=CascadeType.ALL) 例如:

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

答案 1 :(得分:0)

所以我通过使用insertable / updatable = false映射两个超类ParameterParameterType解决了我的问题:

@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;

}

似乎在超类级别强制执行关联就可以了。我不知道它是纯粹的副作用还是设计需要。我没有找到关于这个问题的任何资源。