【问题标题】:Retrieve hierarchical data object with Where clause in root table in Hibernate在 Hibernate 的根表中使用 Where 子句检索分层数据对象
【发布时间】:2017-02-01 11:01:30
【问题描述】:

我有一个小项目,其中我有一个主表,它是表层次结构的根,这个表有一个“ID”和一个“实例 ID”,它们都代表一个主键。这是因为如果行中有任何更改,我想继续跟踪更改。此外,在这个根表中,我有一个属性可以将行标记为“已删除”。

我想要做的是以下查询:给定一个“ID”(第一个)请求,我想获取具有“已删除”属性的单行为 0(这意味着它是当前活动行,因为标记为 1 的行是存储在同一个表中的历史记录的一部分)以及层次结构的后续属性。

例如,如果我有一个名为 Animal 的表,它有一个名为 Dog 的子表,我想通过他的“ID”恢复整个 Dog 对象,这是 Animal 的外键。 Hibernate 有一个能够做到这一点的方法,但问题是如果我想使用它,我不能使用 Where 子句,如果我编写查询,我必须根据子对象类显式编写连接我想得到的。

// This is what I have
public Dog returnAnimalData(String ID) {
    List<Dog> dogs = hibernate.getCurrentSession().get(Dog.class, ID);
    for (Dog dog : dogs) {
        if(dog.getMarkAsDeleted().equals(0)){
            return dog;
        }
    }
    return null;
}

// This is what I would like
public Dog returnAnimalData(String ID) {

    @Where(clause="deleted=0")
    Dog dog = hibernate.getCurrentSession().get(Dog.class, ID);

    // Or 

    Dog dog = hibernate.getCurrentSession().get(Dog.class, ID, 'where deleted = 0');

    return dog;
}

编辑:

一个例子:

Animal 有 ID、InstanceID、deletedFlag 和 typeOfAnimal Dog 有 ID、InstanceID 和 Name,Dog 扩展 Animal Cat 有 ID、InstanceID、Name 和 isFat,Cat 扩展了 Animal

流程是这样的:

Ask for animal 1
 -> Animal 1 is a Dog
 -> search Dog with ID=1 and deletedFlag=0
 -> retrieve Dog (IDs, deletedFlag, animalType, Name)
Ask for animal 2
 -> Animal 2 is a Cat
 -> search Cat with ID=2 and deletedFlag=0
 -> retrieve Cat (IDs, deletedFlag, animalType, Name, isFat)

问题是解决这个查询而不用担心 Animal 的子类的数量,比如“SELECT animal FROM CONCRETE_ANIMAL_TABLE where deletedFlag=0”,其中 CONCRETE_ANIMAL_TABLE 可以是表 Dog、Cat 等的名称。我我会先尝试做纳罗斯的答案。

如果我找到答案,我会发布它,因为我认为这是一个非常有趣的问题,也许它应该有助于理解如何使用 Hibernate 管理层次结构。

【问题讨论】:

    标签: java sql oracle hibernate hierarchical-data


    【解决方案1】:

    您需要使用 HQL/JPQL 来获取您的 Dog 或 JPA Criteria API。由于您使用的是本机 Hibernate API,因此我将在本例中说明 HQL:

    public List<Dog> getDogsByDeletedFlag(boolean deletedFlag) {
      return hibernate.getCurrentSession()
            .createQuery( "SELECT d FROM Dog d WHERE d.deleted = :deletedFlag" )
            .setParameter( "deletedFlag", deletedFlag )
            .getResultList();
    }
    

    Session#getSession#load 方法仅用于通过 identifeir 获取特定实体类型的实例,而不是用于潜在地获取可能结果的列表。

    如果您只想获取第一个命中而不是所有可能的行,则可以对上述查询施加限制约束,例如:

    public Dog getFirstDogByDeletedFlag(boolean deletedFlag) {
      return hibernate.getCurrentSession()
            .createQuery( "SELECT d FROM Dog d WHERE d.deleted = :deletedFlag" )
            .setParameter( "deletedFlag", deletedFlag )
            .setMaxResults( 1 ) // only gets the first hit
            .getSingleResult(); 
    }
    

    更新

    如果您想使用单一方法来获取多态类,您只需传入适当的值即可:

    public <T> T getFirstAnimalByDeletedFlag(Class<T> clazz, boolean deletedFlag) {
      // NOTE: We assume that the class name is also the entity name.
      // Since you can explicitly name entities, e.g. @Entity(name = "MyName"), 
      // you'd need to pass this String value separately if you use this.
    
      StringBuilder sb = new StringBuilder();
      sb.append( "FROM " ).append( clazz.getName() ).append( " o " );
      sb.append(" WHERE o.deleted = :deletedFlag" );
    
      return hibernate.getCurrentSession()
             .createQuery( sb.toString(), clazz )
             .setParameter( "deletedFlag", deletedFlag )
             .setMaxResults( 1 )
             .getSingleResult();
    }
    

    那么您只需调用它:#getFirstAnimalByDeletedFlag( Dog.class, true )#getFirstAnimalByDeletedFlag( Cat.class, true )

    【讨论】:

    • 但我有一点疑问:当你说“SELECT d FROM Dog d...”时,那个“d”变量具有所有超类属性,即 Animal 属性和 Dog 属性?因为我要做的是定义这个方法,以便能够检索我要求的任何子类。我是否能够使用相同的查询检索完整的 Dog 和 Cat?无论如何,我将编辑我的问题以澄清这一点。
    • 有很多方法可以完成您的要求,我在帖子中包含的只是一种。如果我正在开发这个,我可能只是有一个抽象存储库类,它接受一个Class&lt;T&gt; 构造函数参数,然后是一个用于Dog 和一个用于Cat 的存储库实现。从业务代码中,我会根据需要查询CatRepositoryDogRepository。该方法将被共享,我不需要将Class&lt;T&gt; 作为方法参数传递。
    猜你喜欢
    • 2021-10-24
    • 2020-09-21
    • 2016-04-05
    • 2019-10-04
    • 1970-01-01
    • 2020-04-28
    • 2023-03-24
    • 2015-05-26
    • 1970-01-01
    相关资源
    最近更新 更多