13

考虑以下层次结构,其中实体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  {
...

我需要通过 搜索 Widgets serialNumber,但我不知道我在运行时要搜索的 Widget 的具体类型。搜索小部件的正确方法是什么serialNumber,如果serialNumbera 是 a WidgetA,则返回一个实例WidgetA,依此类推?

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

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

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

3 回答 3

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  {
...
于 2013-02-05T20:08:05.937 回答
4

您的对象和注释对我来说看起来不错。我能够拿走它们,将小部件保存到数据库中,然后毫无问题地取出它。

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

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

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

于 2013-02-05T21:26:13.893 回答
2

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

public interface WidgetDAO extends JpaRepository<Widget, Long> {

    @Query("select w from Widget w where w.serialNumer = ?1")
    public Widget findBySerialNumber(String serialNumber);
}
于 2013-01-15T19:33:03.593 回答