Querydsl - low-hill/Knowledge GitHub Wiki

1. ๊ฐœ์š”

Querydsl์€ Hibernate์™€ ๊ฐ™์€ ORM ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํƒ€์ž… ์•ˆ์ „์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ํ›Œ๋ฅญํ•œ ๋Œ€์•ˆ์ž…๋‹ˆ๋‹ค. ๋ฉ”ํƒ€๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํƒ€์ž… ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ๋„, ์ฝ๊ธฐ ์‰ฝ๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค. Querydsl๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๋Š” ๋” ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์ธ ์ฟผ๋ฆฌ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•ด์ง€๋ฉฐ, ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๋” ์ง๊ด€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. Querydsl์˜ ๋ชฉ์ 

๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘(Object-Relational Mapping, ORM) ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ž๋ฐ”์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ORM์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ ๊ฐ„์˜ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋” ๊น”๋”ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ์˜์†์„ฑ ์ฝ”๋“œ ๋ฐ ๋„๋ฉ”์ธ ๋กœ์ง์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋•์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ORM ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์„ค๊ณ„ ์š”์†Œ ์ค‘ ํ•˜๋‚˜๋Š” ์˜ฌ๋ฐ”๋ฅด๊ณ  ํƒ€์ž… ์•ˆ์ „ํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” API์ž…๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ์ž๋ฐ” ORM ํ”„๋ ˆ์ž„์›Œํฌ์ธ Hibernate (๊ทธ๋ฆฌ๊ณ  ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋œ JPA ํ‘œ์ค€)๋Š” SQL๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•œ ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜์˜ ์ฟผ๋ฆฌ ์–ธ์–ด์ธ HQL(๋˜๋Š” JPQL)์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ช…๋ฐฑํ•œ ๋‹จ์ ์€ ํƒ€์ž… ์•ˆ์ „์„ฑ ๋ถ€์กฑ๊ณผ ์ •์  ์ฟผ๋ฆฌ ๊ฒ€์ฆ์˜ ๋ถ€์žฌ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ์—์„œ๋Š” (์˜ˆ๋ฅผ ๋“ค์–ด, ์‹คํ–‰ ์‹œ์ ์— ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ฟผ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ๊ตฌ์„ฑํ•ด์•ผ ํ•  ๋•Œ) ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋งค์šฐ ๋ถˆ์•ˆ์ •ํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

JPA 2.0 ํ‘œ์ค€์—์„œ Criteria Query API๊ฐ€ ๋„์ž…๋˜์–ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด API๋Š” ๋ฉ”ํƒ€๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•ด ํƒ€์ž… ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ–ˆ์œผ๋‚˜, ์ง€๋‚˜์น˜๊ฒŒ ์žฅํ™ฉํ•˜๊ณ  ์ฝ๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ**๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Jakarta EE ํŠœํ† ๋ฆฌ์–ผ์—์„œ SELECT p FROM Pet p์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> query = entityManager.createQuery(cq);
List<Pet> result = query.getResultList();

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๊ธธ๊ณ  ๋ณต์žกํ•˜๊ฒŒ ๋А๊ปด์ง€๋Š” ๊ฒƒ์€ ๋‹น์—ฐํ•œ ์ผ์ž…๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ, ์ƒ์„ฑ๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜๋ฉด์„œ๋„ ๋” ์ง๊ด€์ ์ด๊ณ  ์ฝ๊ธฐ ์‰ฌ์šด API๋ฅผ ์ œ๊ณตํ•˜๋Š” Querydsl ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค. Querydsl์€ ๋ฐ”๋กœ ์ด ์•„์ด๋””์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜์—ฌ, ์ง๊ด€์ ์ด๊ณ  ๊ฐ€๋…์„ฑ ์ข‹์€ API๋กœ ์ฟผ๋ฆฌ ์ž‘์„ฑ ๋ฐฉ์‹์„ ํ˜์‹ ์ ์œผ๋กœ ๊ฐœ์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

3. Querydsl ํด๋ž˜์Šค ์ƒ์„ฑ

์ด์ œ Querydsl์˜ API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฉ”ํƒ€ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

3.1. Maven์— Querydsl ์ถ”๊ฐ€

Querydsl์„ ํ”„๋กœ์ ํŠธ์— ํฌํ•จํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Maven pom.xml ํŒŒ์ผ์— ๋ช‡ ๊ฐ€์ง€ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ , JPA ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋จผ์ € Querydsl ๋ฒ„์ „์„ ์„น์…˜์— ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ Querydsl์˜ ์ตœ์‹  ๋ฒ„์ „์„ Maven Central์—์„œ ํ™•์ธํ•œ ํ›„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<properties>
    <querydsl.version>5.0.0</querydsl.version>
</properties>

๋‹ค์Œ์œผ๋กœ, pom.xml ํŒŒ์ผ์˜ ์„น์…˜์— ์•„๋ž˜์™€ ๊ฐ™์€ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:

<dependencies>
    <!-- Querydsl APT (Annotation Processing Tool) ์˜์กด์„ฑ -->
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
        <classifier>jakarta</classifier>
        <scope>provided</scope>
    </dependency>

    <!-- Querydsl JPA ์˜์กด์„ฑ -->
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <classifier>jakarta</classifier>
        <version>${querydsl.version}</version>
    </dependency>
</dependencies>

querydsl-apt ์˜์กด์„ฑ์€ JPA ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํˆด๋กœ, ์†Œ์Šค ํŒŒ์ผ์„ ์ปดํŒŒ์ผ ์ „์— ์ฒ˜๋ฆฌํ•˜์—ฌ Q-ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, User ํด๋ž˜์Šค๊ฐ€ @Entity ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉด, ์ƒ์„ฑ๋˜๋Š” Q-ํƒ€์ž… ํด๋ž˜์Šค๋Š” QUser.java ํŒŒ์ผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ, apt-maven-plugin ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์ •ํ•˜์—ฌ ๋นŒ๋“œ ๊ณผ์ •์—์„œ Q-ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ Maven ๋นŒ๋“œ ์ค‘ process ๋‹จ๊ณ„์—์„œ Q-ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. outputDirectory๋Š” ์ƒ์„ฑ๋œ ํด๋ž˜์Šค๊ฐ€ ์œ„์น˜ํ•  ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋Š” ์„ค์ •์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ, ์ƒ์„ฑ๋œ ์†Œ์Šค ํŒŒ์ผ์„ IDE์—์„œ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋‹น ํด๋”๋ฅผ ์†Œ์Šค ํด๋”๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ ๋ชจ๋ธ๋กœ, User์™€ BlogPost ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ JPA ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

@Data
@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String login;
    private Boolean disabled;
    @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "user")
    private Set<BlogPost> blogPosts = new HashSet<>(0);
}

@Data
@Entity
public class BlogPost {
    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String body;
    @ManyToOne
    private User user;
}

์œ„ Entity๋กœ Q-ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด, ๋นŒ๋“œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

mvn compile

3.2. ๋นŒ๋“œ๋œ ํด๋ž˜์Šค ํ™•์ธํ•˜๊ธฐ

target/generated-sources/java ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•˜๋ฉด, ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ๋™์ผํ•œ ๊ตฌ์กฐ์˜ ํŒจํ‚ค์ง€์™€ ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋ชจ๋“  ํด๋ž˜์Šค ์ด๋ฆ„์€ Q๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค (QUser, QBlogPost ๋“ฑ).

QUser.java ํŒŒ์ผ์„ ์—ด์–ด๋ณด๋ฉด, ์ด ํด๋ž˜์Šค๊ฐ€ User ์—”ํ‹ฐํ‹ฐ์™€ ๊ด€๋ จ๋œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์—์„œ ๋ˆˆ์— ๋„๋Š” ์ ์€ @Generated ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ด ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฉฐ ์ˆ˜๋™์œผ๋กœ ์ˆ˜์ •ํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๋„๋ฉ”์ธ ๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•œ ํ›„์—๋Š” mvn compile์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ๊ด€๋ จ๋œ ๋ชจ๋“  Q-ํƒ€์ž…์„ ์žฌ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, QUser ํด๋ž˜์Šค์—์„œ ์ฃผ๋ชฉํ•  ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •์  ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค:

public static final QUser user = new QUser("user");

์ด ์ธ์Šคํ„ด์Šค๋Š” ๋Œ€๋ถ€๋ถ„์˜ Querydsl ์ฟผ๋ฆฌ์—์„œ User ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•˜๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ œ์™ธํ•˜๊ณ ๋Š” ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ ํ•„๋“œ๋งˆ๋‹ค ํ•ด๋‹นํ•˜๋Š” *Path ํ•„๋“œ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, QUser ํด๋ž˜์Šค์—๋Š” NumberPath id, StringPath login, SetPath blogPosts์™€ ๊ฐ™์€ ํ•„๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ์ด๋Š” ์ฟผ๋ฆฌ์—์„œ ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํ•„๋“œ๋“ค์€ ๋‚˜์ค‘์— ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” fluent fluent API์˜ ์ผ๋ถ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

4. Querydsl๋กœ ์ฟผ๋ฆฌ ์ž‘์„ฑํ•˜๊ธฐ

4.1. ๊ฐ„๋‹จํ•œ ์กฐํšŒ ๋ฐ ํ•„ํ„ฐ๋ง ์ฟผ๋ฆฌ

์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ๋จผ์ € JPAQueryFactory ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. JPAQueryFactory๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ EntityManager๋ฅผ ํ•„์š”๋กœ ํ•˜๊ณ , ์ด EntityManager๋Š” EntityManagerFactory.createEntityManager() ํ˜ธ์ถœ์ด๋‚˜ @PersistenceContext ์ฃผ์ž…์„ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.baeldung.querydsl.intro");
EntityManager em = emf.createEntityManager();
JPAQueryFactory queryFactory = new JPAQueryFactory(JPQLTemplates.DEFAULT, em);


QUser user = QUser.user;

User c = queryFactory.selectFrom(user)
  .where(user.login.eq("David"))
  .fetchOne();

์œ„ ์ฝ”๋“œ์—์„œ QUser๋Š” QUser.user(ํด๋ž˜์Šค์˜ ์ •์  ์ธ์Šคํ„ด์Šค)๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. selectFrom() ๋ฉ”์„œ๋“œ๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. where() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๋ฉฐ, user.login์€ QUser ํด๋ž˜์Šค์˜ StringPath ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. StringPath๋Š” eq() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ•„๋“œ ๊ฐ’๊ณผ์˜ ๋น„๊ต๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ fetchOne() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฒฐ๊ณผ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๊ฐ€ ์—†์œผ๋ฉด null์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋งŒ์•ฝ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์œผ๋ฉด NonUniqueResultException ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.


Reference

โš ๏ธ **GitHub.com Fallback** โš ๏ธ