我刚刚开始学习在Spring查询中使用Specification
的方法。我写了一个相当复杂的规范,该规范按类型过滤数据库。为了演示,我将展示一个具有相同想法的简单版本:
Specification<Animal> animalWithType(AnimalType type) {
return (root, cq, cb) -> {
return cb.equal(root.get(Animal_.type), type);
};
}
我可以这样称呼animalRepository.findAll(animalWithType(AnimalType.Dog))
,我得到了所有的狗。
现在我也有人类,他们喜欢一种动物。我需要进行查询,以获取所有我们喜欢的动物的人类。为此,我想重用第一个规范,因为它非常复杂。所以我想做这样的事情:
Specification<Human> weHaveFavouriteAnimal() {
return (root, cq, cb) -> {
return cb.exists(animalWithType(root.get(Human_.favouriteAnimalType)));
};
}
我不能这样做有两个原因:
root.get(Human_.favouriteAnimalType)
将给我Expression<AnimalType>
,但我无法传递给我的animalWithType
函数。我也没有一种简单的方法将原始AnimalType转换为Expression<AnimalType>
并随后将其传递,因为我需要QueryBuilder
的实例才能做到这一点。
函数animalWithType
返回一个Specification,但是我需要一个谓词。我假设我需要在此处制作某种类型的SubQuery
,但是我无法将SubQuery
传递给函数Specification::toPredicate
,因为它需要CriteriaQuery。
是否有一种方法可以在另一个规范中为另一个实体重复使用规范作为“存在”子查询?
在SQL中,第一个规范将执行类似select * from animals where type == Dog
的操作,而第二个规范则应将该规范作为子查询并看起来像这样的select * from humans where exists (select * from animals where type == humans.favouriteAnimalType)
。我的SQL有点生锈,但是我希望这不会太遥远。似乎第一个查询在第二个查询中可以很好地重用。我想对“规格”做类似的事情。