# Hibernate 6 criteria subquery

**URL:** <https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118>\
**Category:** Hibernate ORM\
**Created:** [January 23, 2026, 12:35pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118 "2026-01-23T12:35:51Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bence\_Nemeth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/bence_nemeth/32/4263_2.png) [@Bence\_Nemeth](https://discourse.hibernate.org/u/Bence_Nemeth)\
**Post date:** [January 23, 2026, 12:35pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/1 "2026-01-23T12:35:51Z")

</div>

Hibernate 6 subquery number of relations.

org.springframework.dao.InvalidDataAccessResourceUsageException: Error interpreting query [SqmRoot not yet resolved to TableGroup]

What is the correct way of querying the number of related items with Criteria API?

I want to get back the below DTO, I have a OneToMany relation, I am interested about the number of related items.

I could not figure it out with AI, it might be a bug.

Example code: DTO:

```auto
package com.example.demo.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Dto {

    private Long id;

    private Long count;

}

```

Entities:

```auto
package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import lombok.Data;

import java.util.Set;

import static jakarta.persistence.GenerationType.IDENTITY;

@Data
@Entity
public class One {

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

    @OneToMany(mappedBy = "one")
    private Set<Many> many;

}

package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Data;

import static jakarta.persistence.FetchType.LAZY;
import static jakarta.persistence.GenerationType.IDENTITY;

@Data
@Entity
public class Many {

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

    @ManyToOne(fetch = LAZY, optional = false)
    private One one;
}

```

Repository:

```auto
package com.example.demo.repository;

import com.example.demo.dto.Dto;
import com.example.demo.entity.Many;
import com.example.demo.entity.One;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class OneRepositoryCustom {

    private final EntityManager entityManager;

    public List<Dto> query() {

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        CriteriaQuery<Dto> cq = cb.createQuery(Dto.class);
        Root<One> root = cq.from(One.class);

        Subquery<Long> countMany = cq.subquery(Long.class);
        Root<One> correlatedRoot = countMany.correlate(root);
        Root<Many> manyRoot = countMany.from(Many.class);
        countMany.select(cb.count(manyRoot));

        countMany.where(cb.equal(manyRoot.get("one"), correlatedRoot));

        cq.select(cb.construct(Dto.class, root.get("id"), countMany.getSelection()));
        return entityManager.createQuery(cq).getResultList();

    }

}

```

POM.xml

```auto
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>25</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

```

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [January 23, 2026, 12:56pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/2 "2026-01-23T12:56:36Z")

</div>

This is why you still need to understand what you’re doing and can’t just blindly trust the AI..  
You don’t need a subquery to calculate the count, you can just group by the id.

```
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();

    CriteriaQuery<Dto> cq = cb.createQuery(Dto.class);
    Root<One> root = cq.from(One.class);
    SetJoin<Many> manyJoin = root.joinSet("many");

    cq.groupBy(root.get("id"));
    cq.select(cb.construct(Dto.class, root.get("id"), cb.count(cb.literal(1))));
    return entityManager.createQuery(cq).getResultList();

```

---

<div class="post-metadata">

**Author:** ![Bence\_Nemeth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/bence_nemeth/32/4263_2.png) [@Bence\_Nemeth](https://discourse.hibernate.org/u/Bence_Nemeth)\
**Post date:** [January 23, 2026, 1:25pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/3 "2026-01-23T13:25:18Z")

</div>

Yes, thanks, I also got this answer, but it not works with 2 relation, I want a subquery to work please, it was working in previous version.

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [January 23, 2026, 3:51pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/4 "2026-01-23T15:51:16Z")

</div>

Then you have to be more specific.

```
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();

    CriteriaQuery<Dto> cq = cb.createQuery(Dto.class);
    Root<One> root = cq.from(One.class);

    Subquery<Long> countMany = cq.subquery(Long.class);
    Root<One> correlatedRoot = countMany.correlate(root);
    SetJoin<Root, Many> manyJoin = countMany.joinSet("many");
    countMany.select(cb.count(manyJoin));
    cq.select(cb.construct(Dto.class, root.get("id"), countMany));

```

---

<div class="post-metadata">

**Author:** ![Bence\_Nemeth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/bence_nemeth/32/4263_2.png) [@Bence\_Nemeth](https://discourse.hibernate.org/u/Bence_Nemeth)\
**Post date:** [January 23, 2026, 7:43pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/5 "2026-01-23T19:43:02Z")

</div>

I do not see the joinSet method of the Subquery on Jakarta Persistence 3.2.  
What version are you using?  
I do not want my query to contain a join.

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [January 26, 2026, 3:56pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/6 "2026-01-26T15:56:59Z")

</div>

I’m sorry, that’s a typo. It should have been

```
CriteriaBuilder cb = entityManager.getCriteriaBuilder();

CriteriaQuery<Dto> cq = cb.createQuery(Dto.class);
Root<One> root = cq.from(One.class);

Subquery<Long> countMany = cq.subquery(Long.class);
Root<One> correlatedRoot = countMany.correlate(root);
SetJoin<Root, Many> manyJoin = correlatedRoot.joinSet("many");
countMany.select(cb.count(manyJoin));
cq.select(cb.construct(Dto.class, root.get("id"), countMany));

```

---

<div class="post-metadata">

**Author:** ![Bence\_Nemeth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/bence_nemeth/32/4263_2.png) [@Bence\_Nemeth](https://discourse.hibernate.org/u/Bence_Nemeth)\
**Post date:** [February 1, 2026, 3:50pm UTC](https://discourse.hibernate.org/t/hibernate-6-criteria-subquery/12118/7 "2026-02-01T15:50:02Z")

</div>

Works fine, without a join in querry, many thanks.
