JPA继承:Mapped Superclass vs Table Per Class

时间:2016-11-29 10:46:28

标签: java hibernate jpa inheritance

我有一个带有两个子类的抽象父类,我希望子类拥有自己的表。我还有另一个与父类有关系的类:

// Class that has the mapping to the abstract class
@Entity
@Table(name="telephone_numbers")
public class TelephoneNumber implements Serializable {

    @Id
    @Column(name="number")
    private String number;

    @Column(name="originating_carrier")
    private String originatingCarrier;

    @OneToOne(mappedBy = "number")
    private TelephoneNumberAssignment assignment;

... getters and setters ...

}

// Classes involved in inheritance
public abstract class TelephoneNumberAssignment implements Serializable {

    @Id
    @OneToOne
    @JoinColumn(name="number")
    private TelephoneNumber number;

        ... getters and setters ...
}

@Entity
@Table(name="telephone_numbers_fixed_line")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class FixedLineNumberAssignment extends TelephoneNumberAssignment {

    @Column(name="recorded")
    private Boolean recorded;

    public FixedLineNumberAssignment() {
    }

        ... getters and setters ...

}

@Entity
@Table(name="telephone_numbers_mobile")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class MobileNumberAssignment extends TelephoneNumberAssignment {

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;

    public MobileNumberAssignment() {
    }

        ... getters and setters ...

}

根据this question的答案,为了让我的超类中的JPA注释转移到子类,我需要使用@MappedSuperclass。但是,由于需要映射到超类,会发生以下异常:

Caused by: org.hibernate.AnnotationException: Unknown mappedBy in: com.vtsl.domain.numbering.TelephoneNumber.assignment, referenced property unknown: com.vtsl.domain.numbering.TelephoneNumberAssignment.number

根据this question的答案,我可以使用TABLE_PER_CLASS来解决此问题。但是,如果我这样做,我的超类JPA注释似乎不会延续;如果我执行JPQL查询

return entityManager.createQuery("SELECT mob FROM MobileNumberAssignment as mob INNER JOIN FETCH mob.number", MobileNumberAssignment.class).getResultList();

返回的结果没有填充number字段(进一步检查时,我发现hibernate在尝试解析结果对象的属性时没有检测到number属性)。但是,当我执行以下操作时:

//Result set has 1 object
entityManager
    .createQuery("SELECT mob FROM MobileNumberAssignment as mob INNER JOIN FETCH mob.number WHERE mob.number.number = :number", MobileNumberAssignment.class)
    .setParameter("number", "number that exists")
    .getResultList()

//Result set has 0 object
entityManager
    .createQuery("SELECT mob FROM MobileNumberAssignment as mob INNER JOIN FETCH mob.number WHERE mob.number.number = :number", MobileNumberAssignment.class)
    .setParameter("number", "number that does not exist")
    .getResultList()

结果似乎表明该参数毕竟成功解决了。

为什么number属性不会被填充?

1 个答案:

答案 0 :(得分:0)

看来我从症状中得出了所有错误的结论。问题根本不在于继承规范,而在于映射主键的规范。根据我发现的每一种资源

@Id
@OneToOne
@JoinColumn(name="number")
private TelephoneNumber number;

应该工作得很好,但似乎在我使用的hibernate版本(4.10)它没有。更改映射以使用@MapsId解决了我正在观察的问题,使新的(现在正在工作的)TelephoneNumberAssignment看起来像:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class TelephoneNumberAssignment implements Serializable {

    @Id String numberString;

    @MapsId
    @OneToOne
    @JoinColumn(name="number")
    private TelephoneNumber number;

    ... getters and setters ...
}