没有什么可以阻止您使用Specification
(这基本上是Criteria
API 但更易于使用)。您基本上需要以下 JPQL 的动态版本。
SELECT r FROM Recipe r
JOIN r.recipeIngredients ri
JOIN ri.ingredient i
WHERE i.name LIKE :name
现在,如果您可以用 JPQL 编写它,您也可以使用Criteria
API来写它(一般来说)。
public static Specification<Recipe> findByIngredientName(String name) {
return (root, query, criteriaBuilder) -> {
Join<Recipe, RecipeIngredient> ingredients = root.join("ingredients");
Join< RecipeIngredient, Ingredient> ingredient = ingredients.join("ingredient");
return criteriaBuilder.like(ingredient.get("name"), "%" + name + "%");
};
}
这是检索的规范Recipe
含有一个Ingredient
with a name
like
某物。您需要 2 个联接,无需查询,只需一个联接。
您现在甚至可以使用组合多个谓词Predicate.and
。所以如果你创建另一个Predicate
为了Recipe.name
您可以将它们链接在一起,JPA 将处理其余的事情。
public static Specification<Recipe> findName(String name) {
return (root, query, criteriaBuilder) -> {
return criteriaBuilder.like(root.get("title"), "%" + name + "%");
};
}
Specification<Recipe> specs = findByName("recipe").and(findByIngredientName("ingredient"));
recipeRepository.findAll(specs);
这就是你所需要的。您接收哪些参数以及如何接收这些参数取决于您构建请求/响应对象的方式,并且是非常主观的。如果您想要排序顺序,请使用findAll
这需要一个Specification
and a Sort
Specification<Recipe> specs = findByName("recipe").and(findByIngredientName("ingredient"));
recipeRepository.findAll(specs, Sort.by("title"));
上面将生成一个SQL形式
SELECT recipesapp0_.id as id1_1_, recipesapp0_.title as title2_1_ FROM recipes_application$recipe recipesapp0_
INNER JOIN recipes_application$recipe_ingredient recipeingr1_ ON recipesapp0_.id=recipeingr1_.recipe_id
INNER JOIN recipes_application$ingredient recipesapp2_ ON recipeingr1_.ingredient_id=recipesapp2_.id
WHERE (recipesapp0_.title like ?) AND (recipesapp2_.name like ?) ORDER BYrecipesapp0_.title ASC
NOTE:下次当有人要求澄清您的用例时,请明确说明,而不是对他们不友好!