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

考虑以下层次结构,其中实体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搜索Widgets,但我不知道我在运行时搜索的Widget的具体类型。 通过serialNumber搜索小部件的正确方法是什么,这样如果serialNumberWidgetA小部件,那么返回WidgetA的实例,依此类推?

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

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

 public interface WidgetDAO extends JpaRepository { public Widget findBySerialNumber(String serialNumber); } 

您似乎没有为窗口小部件层次结构明确指定鉴别器。 我认为您可以尝试明确定义它,因为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 { ... 

你的对象和注释看起来很好。 我能够将它们保存,将一个小部件保存到数据库中,并且可以毫无问题地将其取出。

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

使用InheritanceType.JOINED ,您可以指定一个鉴别器 ,或者让它为您执行(我相信通过检查子类表中是否存在具有该ID的行)。 但无论哪种方式,您都必须检查数据以确保超类表中没有匹配的子类行。

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

Hibernate支持该查询就好了,并且很乐意返回正确子类的实例。 在不知道正在尝试创建Widget实例的Spring Data实现中它是什么时,您应该能够声明查询并让它直接运行它,而不是使用解析器。

 public interface WidgetDAO extends JpaRepository { @Query("select w from Widget w where w.serialNumer = ?1") public Widget findBySerialNumber(String serialNumber); }