Spring Data JPA(Hibernate):如何仅使用其抽象超类中的字段来检索具体实体?

时间:2013-01-14 22:12:27

标签: java hibernate inheritance jpa spring-data-jpa

考虑以下层次结构,其中实体WidgetAWidgetB扩展了一个抽象的Widget超类:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Widget implements Serializable  {

    @Column(name="serialNumber", length=64, nullable=false, unique=true)
    private String serialNumber;
    ...

@Entity
public class WidgetA extends Widget implements Serializable  {
...

@Entity
public class WidgetB extends Widget implements Serializable  {
...

我需要通过serialNumber搜索小部件,但我不知道我在运行时搜索的小部件的具体类型。按serialNumber搜索小部件的正确方法是,如果serialNumberWidgetA的小部件,则会返回WidgetA的实例,依此类推?

我试图在findyBySerialNumber() DAO中使用Widget,我收到一个错误,告诉我我无法实例化一个抽象类,这是有道理的,但我认为持久性提供者将知道如何查看具体的子实体表并返回正确的实例。我可以这样做吗?

我正在使用“Spring Data JPA”,因此Widget DAO非常简单:

public interface WidgetDAO extends JpaRepository<Widget, Long> {
    public Widget findBySerialNumber(String serialNumber);
}

2 个答案:

答案 0 :(得分:11)

您似乎没有为窗口小部件层次结构明确指定鉴别器。我认为您可以尝试明确定义它,因为Spring Data将操纵字节码来生成查询,因此我怀疑SpringData需要明确定义这些值。

此外,在子类中,您需要指明每个子类的鉴别器值。

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name="WIDGET_TYPE")
public abstract class Widget implements Serializable  {

    @Column(name="serialNumber", length=64, nullable=false, unique=true)
    private String serialNumber;
    ...

-

@Entity
@DiscriminatorValue("A")
public class WidgetA extends Widget implements Serializable  {
...

-

@Entity
@DiscriminatorValue("B")
public class WidgetB extends Widget implements Serializable  {
...

答案 1 :(得分:4)

您的对象和注释对我来说很好看。我能够接受它们,将一个小部件保存到数据库中,并且没有问题地将其取出。

我认为问题出在您的数据中。 Hibernate可能在Widget表中找到一行,在任何子类表中都没有对应的行,因此尝试创建超类的实例,并且失败。

使用InheritanceType.JOINED,您可以指定discriminator,也可以让它为您执行(我相信通过检查子类表中是否存在具有该ID的行)。但不管怎样,你必须检查你的数据,以确保在没有匹配的子类行的超类表中没有条目。

作为一项规则,我支持@ ben75建议您明确指定类层次结构的@Discriminator。最好控制您的鉴别器值,以便以后的代码更改不会以意外的方式改变值。