jpa 使用'WITH RECURSIVE'查询DSL

uwopmtnx  于 2022-12-13  发布在  其他
关注(0)|答案(1)|浏览(370)

此问题存在于querydsl的GitHub问题中。

1.观察到的行为与预期的行为

大家好,我尝试用递归查询得到所有的子类别。

观察到:

Hibernate: 
    with recursive tmp1 (id, parent, name_ko) as ((select
        c.id,
        c.parent,
        c.name_ko 
    from
        car__grade c 
    where
        c.parent is null) 
union
all (select
    p.id,
    p.parent,
    p.name_ko 
from
    tmp1 
inner join
    car__grade p 
        on tmp1 = p.parent)) select
        tmp1.id,
        tmp1.name_ko 
from
    tmp1

所有“parent”都是错误。因为它必须是grade_parent_id。但是,nameKo -〉name_ko已正确更改。

预期行为:

Hibernate: 
    with recursive tmp1 (id, **grade_parent_id**, name_ko) as ((select
        c.id,
        **c.grade_parent_id**,
        c.name_ko 
    from
        car__grade c 
    where
        **c.grade_parent_id** is null) 
union
all (select
    p.id,
    **p.grade_parent_id**,
    p.name_ko 
from
    tmp1 
inner join
    car__grade p 
        on **tmp1.id = p.grade_parent_id**)) select
        tmp1.id,
        tmp1.name_ko 
from
    tmp1

2.重现步骤

我希望你能理解。
//实体

@NoArgsConstructor
@Getter
@DynamicInsert
@DynamicUpdate
@Entity
@Table(name = "car__grade")
public class Grade {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(columnDefinition = "BIGINT(20) UNSIGNED")
  private BigInteger id;

  @Column(name = "name_ko", length = 32, nullable = false,
      columnDefinition = "VARCHAR(32)")
  private String nameKo;

  @OnDelete(action = OnDeleteAction.CASCADE)
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "detail_model_id", nullable = false, updatable = false,
      columnDefinition = "BIGINT(20) UNSIGNED")
  private DetailModel detailModel;

  @QueryInit("*")
  @OneToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "grade_parent_id", columnDefinition = "BIGINT(20) UNSIGNED")
  private Grade parent = null;

  @Builder
  public Grade(String nameKo, DetailModel detailModel) {
    this.nameKo = nameKo;
    this.detailModel = detailModel;
  }

}

//储存库程式码

QGrade tmp1 = new QGrade("tmp1");
    QGrade c = new QGrade("c");
    QGrade p = new QGrade("p");
    PathBuilder<Grade> emp = new PathBuilder<Grade>(Grade.class, "tmp1");

    JPASQLQuery<?> q = new JPASQLQuery<>(em, MySQLTemplates.DEFAULT);
    EntityPathBase<QGrade> rec = new EntityPathBase<>(QGrade.class, "tmp1");

    SQLQuery<Grade> t =
        SQLExpressions.select(Projections.fields(Grade.class, c.id, c.parent, c.nameKo)).from(c)
            .where(c.parent.isNull());
    SQLQuery<Grade> t1 =
        SQLExpressions.select(Projections.fields(Grade.class, p.id, p.parent, p.nameKo)).from(rec)
            .innerJoin(p).on(tmp1.eq(p.parent));
    Union<Grade> union = SQLExpressions.unionAll(t, t1);

    List<Tuple> fetch = q.withRecursive(rec, c.id, c.parent, c.nameKo).as(union)
        .select(tmp1.id, tmp1.nameKo).from(rec).fetch();

c.nameKo、p.nameKo已正确更改,但父级未更改。

// DB(此sql在mysqlworkbench上工作)

WITH RECURSIVE tmp1 (
    `id`,
    `grade_parent_id`,
    `name_ko`
) AS (
    SELECT  id, 
            grade_parent_id,
            name_ko
    FROM    `car__grade`
    WHERE   grade_parent_id IS NULL
    
    UNION ALL
    
    SELECT  r.id,
            r.grade_parent_id,
            r.name_ko
    FROM    `car__grade` AS r
    INNER JOIN tmp1 t
        ON t.id = r.grade_parent_id
)
SELECT * FROM tmp1;

3.环境

Spring Boot 2.4.0
Querydsl版本:4.4.0
查询dsl模块:查询dsl-jpa
数据库:MySQL 8
JDK:11个

4.其他详细信息

我用相同的实体测试了简单的jpa查询。
//简单查询及其结果。

// repo
queryFactory.select(QGrade.grade).from(QGrade.grade).where(QGrade.grade.parent.isNull())
        .fetch();

// console (it works normally especially fields 'parent'.)
Hibernate: 
    select
        grade0_.id as id1_10_,
        grade0_.detail_model_id as detail_m3_10_,
        grade0_.name_ko as name_ko2_10_,
        grade0_.grade_parent_id as grade_pa4_10_ 
    from
        car__grade grade0_ 
    where
        grade0_.grade_parent_id is null
xfb7svmp

xfb7svmp1#

Querydsl 4.x不再维护,我建议升级到5. x。
此外,JPASQLQuery对于复杂的关系连接有许多已知的限制,这就是为什么我通常不鼓励使用JPASQLQuery。相反,我推荐使用Blaze-Persistence Querydsl集成来创建强大的JPQL查询(包括具有递归CTE的查询)。

相关问题