从类层次结构中仅检索超类

4

我有一个如下的方案:

@Entity
@Table(name = "ANIMAL")
@Inheritance(strategy = InheritanceType.JOINED)

public class Animal implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_ANIMAL")
    @SequenceGenerator(name = "S_ANIMAL", sequenceName = "S_ANIMAL", allocationSize = 1)
    public int getNumero() {
        return numero;
    }

    public void setNumero(int numero) {
        this.numero = numero;
    }
        .
        .
        .
}

并且作为子类:

@Entity
@Table(name = "DOG")
public class Dog extends Animal {

    private static final long serialVersionUID = -7341592543130659641L;
        .
        .
        .
}

我有一个类似于这样的JPA查询语句:

SELECT a FROM Animal a;

我正在使用Hibernate 3.3.1

我看到该框架使用左外连接检索 Animal Dog 的实例。

有没有办法仅选择“部分” Animal ?我的意思是,先前的Select 将获取所有 Animal ,即仅为 Animal 而不是 Dog 的那些以及 Dog

我想要它们全部,但对于 Dog ,我只想检索它们的“Animal部分”。

我发现了@org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT),但我发现这仅适用于Animal不是 @Entity 的情况。

非常感谢。

3个回答

3
简短回答:您描述的行为符合JPA标准。没有JPA标准的方式可以限制JPA提供者仅检索超类。
提供程序可以选择查询实现逻辑以实现功能、一致性和性能。只要它尊重您的实体注释并在查询中返回所请求的信息,就没问题了。将Dog的外部连接视为不应关心的私有实现细节。提供程序编码了一个外部连接以协助性能和一致性。
考虑以下内容:
- JPA被定义为在java对象实体而不是表上工作 - 您的实体层次结构的根Animal不是抽象的,因此您可以创建一个实例并将其持久化。 - 您有一个用于Animal的默认值@DescriminatorColumn和@DescriminatorType - 因此将添加一个名为“DTYPE”的鉴别器列,并将类型设置为“一些字符串类型”。您有一个@DescriminatorValue的默认值 - 将等于实体名称:Animal。因此,当您创建此实体时,Animal.DTYPE列=“Animal”。 - 实体狗具有超类Animal。默认值也适用于其@DescriminatorValue - Dog。因此,当您创建此实体时,Animal.DTYPE列=“Dog”。 - Java类限制确保每当存在Dog对象时,相应的Animal超类对象也存在。 - 当您将带有@DescriminatorValue(存储在DTYPE列中的值)=“Dog”的实体Animal加载到JPA持久性上下文中时,通常将Dog对象加载到PC中对于一致性非常有用。即使这不是JPA标准所要求的。 - 继承关系不能指定为EAGER或LAZY(就像基本类型字段或实体关系字段一样)。如果您需要读取/更新dog属性并且未加载Dog类,那么该怎么办?运行单独的查询以重新加载它?这将严重损害一致性和性能。 - 性能的主要问题是发送到DB的单独SQL命令的总数。在时间方面:带有动物表的查询只比带有动物外连接到狗的查询稍快(10微秒???),但比两个单独的查询(一个用于动物,另一个用于狗)快得多。

嗨Luiggi,谢谢你的回答。它对我非常有用,因为你帮助我整理了许多在我脑海中杂乱无章的东西。现在我已经有了有序的事物。JPA行为引发的问题是,当您拥有一个具有属性的@Entity(例如,在我的情况下为jts.Geometry类型),而DB(在我的情况下为Oracle)将其实现为一些属性为VARRAY类型的对象时,尝试使用SELECT DISTINCT时会得到ORA-22901错误。假设在我的案例中,Dog具有Goemetry类型的属性。ORACLE为此使用对象类型SDO_GEOMETRY。 - Gustavo Fava
当使用SELECT DISTINCT a FROM Animal时,JPA会检索Animals和Dogs,因此发送到数据库的SQL语句是select distinct a, b, c ..... 在数据库层面上,b是一个包含两个VARRAY类型属性的"oracle object type",因此Oracle会引发ORA-22901错误。目前我还没有找到解决这个问题的方法。祝好,Gustavo。 - Gustavo Fava
很抱歉,在我的评论中我写了“Hi Luiggi”,但我想感谢Glen Best的回答。我是在stackoverflow上发布帖子的新手,犯了这个错误。我向Glen道歉。问候,Gustavo。 - Gustavo Fava
@GlenBest 我们面临着类似的问题。对我们来说,只获取超类是绝对必要的,因为我们有3个子类和许多急切获取的集合。是否有任何新的解决方案来解决这个问题? - coolscitist
有没有针对这个问题的新解决方案?我认为这里没有任何问题。我不认为会有任何解决方案。需要理解继承的概念。超类+子类总是一起存在。如果你有一个可以独立于对象B存在的对象A,那么这不是祖先关系。 :) - Glen Best

0
其实,有一种方法可以仅获取超类:您只需要使用JPA的本地查询即可。在我的情况下,我正在使用JPA存储库。因此,它应该是这样的:
@Query(value = "SELECT * FROM animal", nativeQuery = true)
List<Resource> findAllAnimal();

将nativeQuery标记设置为true可以在数据库上运行原生SQL。

如果您正在使用实体管理器,请查看此链接:https://www.thoughts-on-java.org/jpa-native-queries/


0
Hibernate使用属性“clazz_”来确定子类。
例如:
select 
  animal0_.animal_id as animal_i1_0_,..., 
  case 
    when animal0_1_.animal_id is not null then 1 
    when animal0_2_.animal_id is not null then 2 
    when animal0_.animal_id is not null then 0 
  end as clazz_
from animal animal0_ 
left outer join dog animal0_1_ on animal0_.animal_id=animal0_1_.animal_id
left outer join cat animal0_2_ on animal0_.animal_id=animal0_2_.animal_id

你应该使用 "0 AS clazz_" 来指定 SQL。

@Query(value = "SELECT *, 0 AS clazz_ FROM animal", nativeQuery = true)
List<Animal> findAllAnimal();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接