使用Hibernate中根表中的Where子句检索分层数据对象



我有一个小项目,其中有一个主表,它是表层次结构的根,这个表有一个"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;
}

编辑:

一个例子:

动物具有ID、InstanceID、deletedFlag和typeOfAnimalDog有ID、InstanceID和Name,Dog扩展了AnimalCat具有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 CONCRTE_Animal_TABLE where deletedFlag=0",其中CONCERTE_Animal_TABLE可以是表Dog、Cat等的名称。我会先尝试做Naros的答案。

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

您需要使用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仅用于通过identifier获取特定实体类型的实例,而不用于潜在地获取可能结果的列表。

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

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 )

最新更新