Java 使用QueryDSL和JPASQLQuery连接多对多关系
我拥有以下实体:Java 使用QueryDSL和JPASQLQuery连接多对多关系,java,jpa,querydsl,Java,Jpa,Querydsl,我拥有以下实体: @AllArgsConstructor @EqualsAndHashCode(of = {"name"}) @Data @NoArgsConstructor @Entity @Table(schema = "eat") public class Pizza { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="pizza_id_se
@AllArgsConstructor
@EqualsAndHashCode(of = {"name"})
@Data
@NoArgsConstructor
@Entity
@Table(schema = "eat")
public class Pizza {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="pizza_id_seq")
private Integer id;
@NotNull
private String name;
@NotNull
@Positive
private Double cost;
@ManyToMany
@JoinTable(schema = "eat",
name = "pizza_ingredient",
inverseJoinColumns = { @JoinColumn(name = "ingredient_id") })
private Set<Ingredient> ingredients;
}
@AllArgsConstructor
@EqualsAndHashCode(of = {"name"})
@Data
@NoArgsConstructor
@Entity
@Table(schema = "eat")
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="ingredient_id_seq")
private Integer id;
@NotNull
@Size(min=1, max=64)
private String name;
}
问题出现在尝试使用join
函数时,例如:
QIngredient ingredient = QIngredient.ingredient;
QPizza pizza = QPizza.pizza;
StringPath ingredientPath = Expressions.stringPath("ingredient");
StringPath pizzaPath = Expressions.stringPath("pizza");
NumberPath<Double> costPath = Expressions.numberPath(Double.class, "cost");
Expression rowNumber = SQLExpressions.rowNumber().over().partitionBy(ingredientPath).orderBy(costPath.desc()).as("rnk");
JPASQLQuery subQuery = getJPASQLQuery()
.select(ingredient.name.as(ingredientPath), pizza.name.as(pizzaPath), pizza.cost.as(costPath), rowNumber)
.from(pizza)
// The error is in next innerJoin
.innerJoin((SubQueryExpression<?>) pizza.ingredients, ingredient)
.where(ingredient.name.in(ingredientNames));
@Table(schema = "eat")
public class Pizza ...
我无法删除当前的(SubQueryExpression)
,因为innerJoin
不接受SetPath
作为参数
另一方面,以下方面:
.from(pizza)
.innerJoin(ingredient)
由于生成的查询中未包含pizza\u配料
,因此不起作用
如何将
JPASQLQuery
中的innerJoin
与上述多对多关系一起使用?基本上,有两种主要的解决方法:
包括必需的本机函数 正如一位QueryDSL开发人员所建议的,用JPA替代品取代
JPASQLQuery
为多对多表创建所需的路径 首先,将
name
属性添加到每个@表
注释中非常重要,因为内部是QueryDSLNativeSQLSerializer
类用于从和联接
子句生成
例如:
QIngredient ingredient = QIngredient.ingredient;
QPizza pizza = QPizza.pizza;
StringPath ingredientPath = Expressions.stringPath("ingredient");
StringPath pizzaPath = Expressions.stringPath("pizza");
NumberPath<Double> costPath = Expressions.numberPath(Double.class, "cost");
Expression rowNumber = SQLExpressions.rowNumber().over().partitionBy(ingredientPath).orderBy(costPath.desc()).as("rnk");
JPASQLQuery subQuery = getJPASQLQuery()
.select(ingredient.name.as(ingredientPath), pizza.name.as(pizzaPath), pizza.cost.as(costPath), rowNumber)
.from(pizza)
// The error is in next innerJoin
.innerJoin((SubQueryExpression<?>) pizza.ingredients, ingredient)
.where(ingredient.name.in(ingredientNames));
@Table(schema = "eat")
public class Pizza ...
应替换为:
@Table(name = "pizza", schema = "eat")
public class Pizza ...
接下来,为多对多表的自定义路径创建:
RelationalPathBase<Object> pizzaIngredient = new RelationalPathBase<>(Object.class, "pi", "eat", "pizza_ingredient");
NumberPath<Integer> pizzaIngredient_PizzaId = Expressions.numberPath(Integer.class, pizzaIngredient, "pizza_id");
NumberPath<Integer> pizzaIngredient_IngredientId = Expressions.numberPath(Integer.class, pizzaIngredient, "ingredient_id");
RelationalPathBase PizzaComponent=新的RelationalPathBase(Object.class,“pi”,“eat”,“pizza_配料”);
NumberPath PizzaComponent_PizzaId=Expressions.NumberPath(Integer.class,pizzaComponent,“pizza_id”);
NumberPath PizzaComponent\u IngredenId=Expressions.NumberPath(Integer.class,PizzaComponent,“Component\u id”);
因此,完整的代码是:
QIngredient ingredient = QIngredient.ingredient;
QPizza pizza = QPizza.pizza;
RelationalPathBase<Object> pizzaIngredient = new RelationalPathBase<>(Object.class, "pi", "eat", "pizza_ingredient");
NumberPath<Integer> pizzaIngredient_PizzaId = Expressions.numberPath(Integer.class, pizzaIngredient, "pizza_id");
NumberPath<Integer> pizzaIngredient_IngredientId = Expressions.numberPath(Integer.class, pizzaIngredient, "ingredient_id");
StringPath ingredientPath = Expressions.stringPath("ingredient");
StringPath pizzaPath = Expressions.stringPath( "pizza");
NumberPath<Double> costPath = Expressions.numberPath(Double.class, "cost");
Expression rowNumber = SQLExpressions.rowNumber().over().partitionBy(ingredientPath).orderBy(costPath.desc()).as("rnk");
NumberPath<Long> rnk = Expressions.numberPath(Long.class, "rnk");
SubQueryExpression subQuery = getJPASQLQuery()
.select(ingredient.name.as(ingredientPath), pizza.name.as(pizzaPath), pizza.cost.as(costPath), rowNumber)
.from(pizza)
.innerJoin(pizzaIngredient).on(pizzaIngredient_PizzaId.eq(pizza.id))
.innerJoin(ingredient).on(ingredient.id.eq(pizzaIngredient_IngredientId))
.where(ingredient.name.in(ingredientNames));
return getJPASQLQuery()
.select(ingredientPath, pizzaPath, costPath)
.from(
subQuery,
Expressions.stringPath("temp")
)
.where(rnk.eq(1l))
.fetch();
QIngredient-component=QIngredient.component;
QPizza比萨饼=QPizza.pizza;
RelationalPathBase PizzaComponent=新的RelationalPathBase(Object.class,“pi”,“eat”,“pizza_配料”);
NumberPath PizzaComponent_PizzaId=Expressions.NumberPath(Integer.class,pizzaComponent,“pizza_id”);
NumberPath PizzaComponent\u IngredenId=Expressions.NumberPath(Integer.class,PizzaComponent,“Component\u id”);
StringPath ingredientPath=Expressions.StringPath(“成分”);
StringPath pizzaPath=Expressions.StringPath(“pizzaPath”);
NumberPath costPath=Expressions.NumberPath(Double.class,“cost”);
表达式rowNumber=SQLExpressions.rowNumber().over().partitionBy(IngreditEntPath).orderBy(costPath.desc()).as(“rnk”);
NumberPath rnk=Expressions.NumberPath(Long.class,“rnk”);
SubQueryExpression subQuery=getJPASQLQuery()
.选择(配料.name.as(IngreditPath)、pizza.name.as(pizzaPath)、pizza.cost.as(costPath)、rowNumber)
.来自(比萨饼)
.innerJoin(PizzaComponent).on(PizzaComponent_PizzaId.eq(pizza.id))
.innerJoin(配料).on(配料.id.eq(比萨配料)
.其中(成分名称)在(IngreditNames)中;
返回getJPASQLQuery()
.选择(IngreditPath、pizzaPath、costPath)
.来自(
子查询,
表达式.stringPath(“temp”)
)
.式中(rnk等式(1l))
.fetch();