繁体   English   中英

在 Spring 数据 JPA 中使用 @Query 进行动态查询?

[英]Dynamic query with @Query in Spring Data JPA?

我在我的 Spring 引导应用程序中使用规范,可以通过不同的过滤器选项过滤结果。 但是,我需要在我的存储库方法中使用带有@Query的特殊过滤器,据我所知,我无法在此查询中构建动态 WHERE 子句。

还有 QueryDSL 和 CriteriaAPI 选项,但我找不到在@Query中使用它们的示例。

那么,是否可以动态构建 WHERE 子句或为@Query中的查询创建过滤器? 这是我的方法:

// there are more filters that omitted for brevity 

@Query("SELECT r FROM Recipe r WHERE r.title LIKE %:text%")
Page<Recipe> findByFields(@Param("text") String text);

我尝试在此方法中使用我的规范,但无法将它们与@Query一起使用 :((



更新:


@Entity
public class Recipe {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @Enumerated(value = EnumType.STRING)
    private HealthLabel healthLabel;

    // code omitted for brevity

    @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RecipeIngredient> recipeIngredients = new ArrayList<>();
}

@Entity
public class RecipeIngredient {

    @EmbeddedId
    private RecipeIngredientId recipeIngredientId = new RecipeIngredientId();

    @Column(nullable = false)
    private BigDecimal amount;

    @ManyToOne(optional = true, fetch = FetchType.LAZY)
    @MapsId("recipeId")
    @JoinColumn(name = "recipe_id", referencedColumnName = "id")
    private Recipe recipe;

    @ManyToOne(optional = true, fetch = FetchType.LAZY)
    @MapsId("ingredientId")
    @JoinColumn(name = "ingredient_id", referencedColumnName = "id")
    private Ingredient ingredient;
}

@Entity
public class Ingredient {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false, length = 50)
    private String name;

    @OneToMany(mappedBy = "ingredient", cascade = CascadeType.ALL)
    private Set<RecipeIngredient> recipeIngredients = new HashSet<>();
}

这也是我无法过滤的枚举:

@Getter
@AllArgsConstructor
public enum HealthLabel {

    DEFAULT("Default"),
    EGG_FREE("Egg-free"),
    VEGETARIAN("Vegetarian"),
    WHEAT_FREE("Wheat-free");

    private String label;
}

@Query只能进行 static 次查询。

如果你想要更动态的东西,你必须使用另一个特性,例如Specifications或者甚至回退到自定义方法实现

你可以这样尝试:

@Query("SELECT r FROM Recipe r WHERE r.title LIKE %?1%")
Page<Recipe> findByFields(String text);

没有什么可以阻止您使用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 + "%"); 
  };
}

这是用于检索包含name like某物的IngredientRecipe的规范。 您需要 2 个连接,无需查询,只需一个连接。

您现在甚至可以使用Predicate.and组合多个谓词。 因此,如果您为Recipe.name创建另一个Predicate ,您可以将它们链接在一起,JPA 将处理 rest。

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和一个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

注意:下次当有人要求澄清你的用例时,请给出而不是对他们不友好!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM