java—使用querydsl和jpasqlquery连接多对多关系

idv4meu8  于 2021-07-12  发布在  Java
关注(0)|答案(1)|浏览(525)

我有以下实体:

  1. @AllArgsConstructor
  2. @EqualsAndHashCode(of = {"name"})
  3. @Data
  4. @NoArgsConstructor
  5. @Entity
  6. @Table(schema = "eat")
  7. public class Pizza {
  8. @Id
  9. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="pizza_id_seq")
  10. private Integer id;
  11. @NotNull
  12. private String name;
  13. @NotNull
  14. @Positive
  15. private Double cost;
  16. @ManyToMany
  17. @JoinTable(schema = "eat",
  18. name = "pizza_ingredient",
  19. inverseJoinColumns = { @JoinColumn(name = "ingredient_id") })
  20. private Set<Ingredient> ingredients;
  21. }
  22. @AllArgsConstructor
  23. @EqualsAndHashCode(of = {"name"})
  24. @Data
  25. @NoArgsConstructor
  26. @Entity
  27. @Table(schema = "eat")
  28. public class Ingredient {
  29. @Id
  30. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="ingredient_id_seq")
  31. private Integer id;
  32. @NotNull
  33. @Size(min=1, max=64)
  34. private String name;
  35. }

我在用 JPASQLQuery querydsl(4.2.2)提供的用于在postgresql中创建一些本机查询的对象:

  1. public JPASQLQuery<T> getJPASQLQuery() {
  2. return new JPASQLQuery<>(
  3. entityManager,
  4. PostgreSQLTemplates.builder().printSchema().build()
  5. );
  6. }

问题出在尝试使用 join 函数,例如:

  1. QIngredient ingredient = QIngredient.ingredient;
  2. QPizza pizza = QPizza.pizza;
  3. StringPath ingredientPath = Expressions.stringPath("ingredient");
  4. StringPath pizzaPath = Expressions.stringPath("pizza");
  5. NumberPath<Double> costPath = Expressions.numberPath(Double.class, "cost");
  6. Expression rowNumber = SQLExpressions.rowNumber().over().partitionBy(ingredientPath).orderBy(costPath.desc()).as("rnk");
  7. JPASQLQuery subQuery = getJPASQLQuery()
  8. .select(ingredient.name.as(ingredientPath), pizza.name.as(pizzaPath), pizza.cost.as(costPath), rowNumber)
  9. .from(pizza)
  10. // The error is in next innerJoin
  11. .innerJoin((SubQueryExpression<?>) pizza.ingredients, ingredient)
  12. .where(ingredient.name.in(ingredientNames));

如果我保持电流 innerJoin((SubQueryExpression<?>) pizza.ingredients, ingredient) 我收到:

  1. class com.querydsl.core.types.dsl.SetPath cannot be cast to class com.querydsl.core.types.SubQueryExpression

我不能移除当前 (SubQueryExpression<?>) 因为 innerJoin 不接受 SetPath 作为参数。
另一方面,以下是:

  1. .from(pizza)
  2. .innerJoin(ingredient)

由于以下原因无法工作 pizza_ingredient 不包括在生成的查询中。
我怎么用 innerJoinJPASQLQuery 像这样的多对多关系?

3pmvbmvn

3pmvbmvn1#

基本上,有两种主要的解决方法:

包括必需的本机函数

正如一位querydsl开发人员所建议的,替换 JPASQLQuery jpa的替代品。

为多对多表创建所需路径

首先要补充一点 name 每个 @Table 注解,因为内部是querydsl使用的注解 NativeSQLSerializer 要生成的类 from 以及 join 条款。
例如:

  1. @Table(schema = "eat")
  2. public class Pizza ...

应替换为:

  1. @Table(name = "pizza", schema = "eat")
  2. public class Pizza ...

接下来,为自定义创建 Path 对于多对多表:

  1. RelationalPathBase<Object> pizzaIngredient = new RelationalPathBase<>(Object.class, "pi", "eat", "pizza_ingredient");
  2. NumberPath<Integer> pizzaIngredient_PizzaId = Expressions.numberPath(Integer.class, pizzaIngredient, "pizza_id");
  3. NumberPath<Integer> pizzaIngredient_IngredientId = Expressions.numberPath(Integer.class, pizzaIngredient, "ingredient_id");

所以完整的代码是:

  1. QIngredient ingredient = QIngredient.ingredient;
  2. QPizza pizza = QPizza.pizza;
  3. RelationalPathBase<Object> pizzaIngredient = new RelationalPathBase<>(Object.class, "pi", "eat", "pizza_ingredient");
  4. NumberPath<Integer> pizzaIngredient_PizzaId = Expressions.numberPath(Integer.class, pizzaIngredient, "pizza_id");
  5. NumberPath<Integer> pizzaIngredient_IngredientId = Expressions.numberPath(Integer.class, pizzaIngredient, "ingredient_id");
  6. StringPath ingredientPath = Expressions.stringPath("ingredient");
  7. StringPath pizzaPath = Expressions.stringPath( "pizza");
  8. NumberPath<Double> costPath = Expressions.numberPath(Double.class, "cost");
  9. Expression rowNumber = SQLExpressions.rowNumber().over().partitionBy(ingredientPath).orderBy(costPath.desc()).as("rnk");
  10. NumberPath<Long> rnk = Expressions.numberPath(Long.class, "rnk");
  11. SubQueryExpression subQuery = getJPASQLQuery()
  12. .select(ingredient.name.as(ingredientPath), pizza.name.as(pizzaPath), pizza.cost.as(costPath), rowNumber)
  13. .from(pizza)
  14. .innerJoin(pizzaIngredient).on(pizzaIngredient_PizzaId.eq(pizza.id))
  15. .innerJoin(ingredient).on(ingredient.id.eq(pizzaIngredient_IngredientId))
  16. .where(ingredient.name.in(ingredientNames));
  17. return getJPASQLQuery()
  18. .select(ingredientPath, pizzaPath, costPath)
  19. .from(
  20. subQuery,
  21. Expressions.stringPath("temp")
  22. )
  23. .where(rnk.eq(1l))
  24. .fetch();
展开查看全部

相关问题