【问题标题】:Retrieve only the superclass from a class hierarchy仅从类层次结构中检索超类
【发布时间】:2012-11-01 22:37:31
【问题描述】:

我有一个场景如下:

@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 语句:

SELECT a FROM Animal a;

我使用的是 Hibernate 3.3.1

正如我所见,框架使用左外连接检索AnimalDog 的实例。

有没有办法只选择“部分”Animal?我的意思是,之前的Select 将得到所有的Animals,那些只有Animals 但不是Dogs 的那些以及那些Dogs 的。

我想要所有这些,但对于Dogs,我只想检索它们的“动物部分”。

我找到了@org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT) 但正如我所见,这只有在 Animal 不是 @Entity 时才有效。

非常感谢。

【问题讨论】:

    标签: java hibernate jpa class-hierarchy


    【解决方案1】:

    简短回答:您描述的行为符合 JPA 标准。没有 JPA 标准方法来限制 JPA 提供者只检索超类。

    提供者可以选择查询实现逻辑来实现功能、一致性和性能。只要它尊重您的实体注释并在查询中返回请求的信息,一切都很好。将 Dog 的外部连接视为您不应该关心的私有实现细节。提供者已对外部连接进行编码以提高性能和一致性。

    考虑:

    • JPA 被定义为适用于 java 对象实体而不是表
    • 实体层次结构的根 Animal 不是抽象的,因此您可以创建一个实例并将其持久化。
    • Animal @DescriminatorColumn 和 @DecriminatorType 有一个默认值 - 因此 Animal 表将添加一个名称为“DTYPE”并键入“某些字符串类型”的鉴别器列。 @DecriminatorValue 有一个默认值 - 将等于实体名称:Animal。所以 Animal.DTYPE column = "Animal" 当你创建这个实体时。
    • 实体狗有一个超类动物。默认值也用于其@DecriminatorValue - Dog。所以 Animal.DTYPE column = "Dog" 当你创建这个实体时。
    • Java 类限制确保只要存在 Dog 对象,相应的 Animal 超类对象也存在。
    • 通常,当您将实体 Animal 加载到 JPA 持久性上下文中时,并且 @DecriminatorValue(存储在 DTYPE 列中的值)=“Dog”,那么将 Dog 对象加载到 PC 中以保持一致性非常有用。尽管 JPA 标准并不要求这样做。
    • 不能将继承关系指定为 EAGER 或 LAZY(如基本类型字段或实体关系字段)。如果您需要读取/更新狗属性并且未加载 Dog 类,您会怎么做?运行一个单独的查询来重新加载它?这会极大地损害一致性和性能。
    • 性能的主要关注点是发送到数据库的单独 SQL 命令的总数。
      就所用时间而言: 使用动物表进行查询仅比使用动物外部连接到狗的查询快一点(10 微秒???),但比两个单独的查询(一个用于动物,一个用于狗)快得多

    【讨论】:

    • 嗨 Luiggi,感谢您的回答。这对我来说非常有用,因为您帮助我订购了许多在我脑海中但以混乱方式出现的东西。现在我把事情整理好了。 JPA 行为引起的问题是,当您有一个具有属性的@Entity(例如,在我的情况下是 jts.Geometry 类型)时,DB(在我的情况下是 Oracle)作为对象实现,其中一些它的属性是 VARRAY 类型,当您尝试 SELECT DISTINCT 时,您会得到 ORA-22901。假设在我的情况下 Dog 具有 Goemetry 类型的属性。 ORACLE 为其使用对象类型 SDO_GEOMETRY。
    • 当 SELECT DISTINCT a FROM Animal 时,JPA 检索 Animals 和 Dogs,因此进入数据库的 sql 选择了不同的 a、b、c .....并且在数据库级别 b 是“ oracle object type”包含 VARRAY 类型的 2 个属性,Oracle 上升 ORA-22901。我还找不到解决方法。问候,古斯塔沃。
    • 对不起,我在评论中写了“Hi Luiggi”,但我想感谢 Glen Best 的回答。我是在 stackoverflow 上发帖的新手,我犯了一个错误。我为我的错误向格伦道歉。问候,古斯塔沃。
    • @GlenBest 我们面临着类似的问题。对我们来说,只获取超类是绝对必要的,因为我们有 3 个子类以及许多急切获取的集合。这个问题有什么新的解决办法吗?
    • '这个问题有什么新的解决办法吗?'我不认为这里有任何问题。我认为不会有任何解决方案。需要理解继承的概念。超类+子类总是一起存在的。如果您有可以独立于对象 B 存在的对象 A - 那么这不是祖先关系。 :)
    【解决方案2】:

    实际上,有一种方法可以只获取超类:您只需要使用来自 JPA 的本机查询。就我而言,我使用的是 JPA 存储库。因此,它会是这样的:

    @Query(value = "SELECT * FROM animal", nativeQuery = true)
    List<Resource> findAllAnimal();
    

    将 nativeQuery 标记为 true 允许在数据库上运行本机 SQL。

    如果您使用的是实体管理器,请查看:https://www.thoughts-on-java.org/jpa-native-queries/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多