AI 에이전트의 경우: 문서 인덱스는 https://www.mongodb.com/ko-kr/docs/llms.txt에서 사용할 수 있으며, 모든 페이지의 마크다운 버전은 어떤 URL 경로에 .md를 추가하여 사용할 수 있습니다.
See how MongoDB 9.0 delivers up to 2x higher throughput.
MongoDB Branding Shape
Register now >
Docs Menu

컬렉션 간 엔터티 조인

이 가이드 에서는 최대 절전 모드 ORM용 MongoDB 확장을 사용하여 연관 관계로 연결된 엔터티를 쿼리 하는 방법을 학습 수 있습니다. 최대 절전 모드 쿼리 언어(HQL) 또는 자카르타 지속성 쿼리 언어(JPQL)를 사용할 수 있습니다.

엔터티를 조인하려면 조인 절에서 연결 경로를 탐색하거나 조인 절에서 엔터티의 이름을 지정하고 ON 절을 제공하면 됩니다. 연관 관계 조인에 ON 절을 추가할 수도 있습니다.

최대 절전 모드 ORM 확장은 각 조인을 MongoDB $lookup 단계와 $unwind 단계로 변환합니다.

참고

ON 조건의 참조 열

ON 조건은 열을 비교해야 합니다. 하이버네이트 ORM 확장은 on m = c.movie에서와 같이 엔터티 참조를 비교하거나 on c.movie.title = 'Blue Jasmine'에서와 같이 조건 내 연결 탐색을 지원 하지 않습니다. 이 가이드 의 복합 키 조인 섹션에 설명된 대로 두 개의 전체 복합 식별자를 비교할 수 있습니다. 최대 절전 모드 ORM 확장이 지원하는 조인 유형을 학습 기능 호환성 페이지의 쿼리 지원을 참조하세요.

이 가이드 의 예제에서는 Atlas 샘플 데이터 세트의 sample_mflix.movies 컬렉션 나타내는 Movie 엔터티를 사용합니다. Movie 엔터티의 정의는 다음과 같습니다.

import com.mongodb.hibernate.annotations.ObjectIdGenerator;
import org.bson.types.ObjectId;
import java.time.Instant;
import java.util.List;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@Entity
@Table(name = "movies")
public class Movie {
@Id
@ObjectIdGenerator
private ObjectId id;
private String title;
private String plot;
private int year;
private List<String> cast;
private List<String> directors;
private Instant released;
@Embedded
private Awards awards;
@OneToMany(mappedBy = "movie", fetch = FetchType.LAZY)
private List<Comment> comments;
public Movie(String title, String plot, int year, List<String> cast, List<String> directors, Instant released, Awards awards) {
this.title = title;
this.plot = plot;
this.year = year;
this.cast = cast;
this.directors = directors;
this.released = released;
this.awards = awards;
}
public Movie() {
}
public ObjectId getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPlot() {
return plot;
}
public void setPlot(String plot) {
this.plot = plot;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public List<String> getCast() {
return cast;
}
public void setCast(List<String> cast) {
this.cast = cast;
}
public List<String> getDirectors() {
return directors;
}
public void setDirectors(List<String> directors) {
this.directors = directors;
}
public Awards getAwards() {
return awards;
}
public void setAwards(Awards awards) {
this.awards = awards;
}
public Instant getReleased() {
return released;
}
public void setReleased(Instant released) {
this.released = released;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
}

최대 절전 모드용 MongoDB 확장 ORM을 사용하여 이 MongoDB 샘플 컬렉션과 상호 작용하는 Java 애플리케이션 만드는 방법을 학습하려면 시작하기 튜토리얼을 참조하세요.

이 페이지의 예시는 sample_mflix.movies 컬렉션 sample_mflix.comments 컬렉션 에 조인합니다. comments 컬렉션 의 문서는 movie_id 필드 에 설명하는 영화의 _id 값을 저장 .

Movie 엔티티는 comments 필드 참조하는 Comment 엔티티에 매핑합니다. 영화의 출시하다 은 Movie 엔터티의 released 필드 에 저장됩니다.

다음 Comment 엔티티는 comments 컬렉션 에 매핑되고 해당 movie 필드 에서 관련 Movie 엔티티를 참조합니다.

package org.example;
import com.mongodb.hibernate.annotations.ObjectIdGenerator;
import jakarta.persistence.Column;
import org.bson.types.ObjectId;
import java.time.Instant;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Entity
@Table(name = "comments")
public class Comment {
@Id
@ObjectIdGenerator
@Column(name = "_id")
private ObjectId id;
private String name;
private String email;
private String text;
private Instant date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "movie_id")
private Movie movie;
public Comment(String name, String email, String text, Instant date, Movie movie) {
this.name = name;
this.email = email;
this.text = text;
this.date = date;
this.movie = movie;
}
public Comment() {
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Instant getDate() {
return date;
}
public void setDate(Instant date) {
this.date = date;
}
public Movie getMovie() {
return movie;
}
public void setMovie(Movie movie) {
this.movie = movie;
}
}

복합 ON 조건 섹션의 예시에서는 sample_mflix.users 컬렉션 에 매핑되는 다음 User 엔터티도 사용합니다.

package org.example;
import com.mongodb.hibernate.annotations.ObjectIdGenerator;
import jakarta.persistence.Column;
import org.bson.types.ObjectId;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
@ObjectIdGenerator
@Column(name = "_id")
private ObjectId id;
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public User() {
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

내부 조인은 연결의 양쪽이 일치하는 엔터티만 반환합니다.

다음 예시 내부 조인을 사용하여 2015에 개봉된 각 영화의 제목과 이에 댓글을 단 각 사람의 이름을 조회 . 댓글이 없는 영화는 결과에서 제외됩니다.

var innerJoinResults = session.createQuery("select m.title, c.name from Movie m join m.comments c where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : innerJoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}
var innerJoinResults = entityManager.createQuery("select m.title, c.name from Movie m join m.comments c where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : innerJoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}

최대 절전 모드 ORM 확장은 이전 조인을 다음 단계로 변환합니다.

{
"$lookup": {
"from": "comments",
"localField": "_id",
"foreignField": "movie_id",
"as": "#c1_0"
}
},
{ "$unwind": "$#c1_0" }

하이버네이트 ORM 확장은 쿼리 성명서 에서 as 필드 이름을 생성하고 이를 사용하여 파이프라인 의 이후 단계에서 조인된 필드를 참조합니다.

왼쪽 외부 조인은 오른쪽에 일치하는 항목이 없는 엔터티를 포함하여 연관 관계의 왼쪽에 있는 모든 엔터티를 반환합니다. 오른쪽에서 일치하는 항목이 없는 엔터티는 조인의 오른쪽에 대해 null 결과를 반환합니다.

다음 예시 왼쪽 외부 조인을 사용하여 2015에 개봉된 각 영화의 제목과 함께 댓글을 단 각 사람의 이름을 조회 . 댓글이 없는 영화는 결과에 포함됩니다.

var leftJoinResults = session.createQuery("select m.title, c.name from Movie m left join m.comments c where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : leftJoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}
var leftJoinResults = entityManager.createQuery("select m.title, c.name from Movie m left join m.comments c where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : leftJoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}

최대 절전 모드 ORM 확장은 이전 조인을 다음 단계로 변환합니다. preserveNullAndEmptyArrays 옵션은 일치하는 댓글이 없는 영화를 유지합니다.

{
"$lookup": {
"from": "comments",
"localField": "_id",
"foreignField": "movie_id",
"as": "#c1_0"
}
},
{
"$unwind": {
"path": "$#c1_0",
"preserveNullAndEmptyArrays": true
}
}

하이버네이트 ORM 확장은 쿼리 성명서 에서 as 필드 이름을 생성하고 이를 사용하여 파이프라인 의 이후 단계에서 조인된 필드를 참조합니다.

JOIN FETCH 절은 상위 항목과 동일한 쿼리 에서 연결된 엔터티를 로드하므로 세션이 닫힌 후에도 연결 액세스 할 수 있습니다.

다음 예시 JOIN FETCH 절을 사용하여 주석을 조회 하고 각 주석이 참조하는 Movie 엔티티를 로드합니다.

var comments = session.createQuery("from Comment c join fetch c.movie where c.name = :n", Comment.class)
.setParameter("n", "Andrea Le")
.getResultList();
for (var c : comments) {
System.out.println("Commenter: " + c.getName() + ", Title: " + c.getMovie().getTitle());
}
var comments = entityManager.createQuery("select c from Comment c join fetch c.movie where c.name = :n", Comment.class)
.setParameter("n", "Andrea Le")
.getResultList();
for (var c : comments) {
System.out.println("Commenter: " + c.getName() + ", Title: " + c.getMovie().getTitle());
}

하이버네이트 ORM 확장은 JOIN FETCH 절을 동등한 조인과 동일한 파이프라인 단계로 변환합니다.

ON 조건은 AND 또는 OR와 여러 필드 비교를 결합할 수 있습니다. 둘 이상의 필드 와 관련된 엔터티를 조인하려면 복합 조건을 사용합니다. 복합 기본 키 있는 엔터티를 조인하려면 이 가이드 의 복합 키 조인 섹션을 참조하세요.

다음 예시 name 및 email 필드 모두에서 users 및 comments 컬렉션을 조인하여 두 필드가 동일한 경우에만 댓글이 사용자와 일치하도록 합니다.

var compoundOnResults = session.createQuery("select u.name, c.text from User u join Comment c on u.name = c.name and u.email = c.email", Object[].class)
.getResultList();
for (var row : compoundOnResults) {
System.out.println("Name: " + row[0] + ", Comment: " + row[1]);
}
var compoundOnResults = entityManager.createQuery("select u.name, c.text from User u join Comment c on u.name = c.name and u.email = c.email", Object[].class)
.getResultList();
for (var row : compoundOnResults) {
System.out.println("Name: " + row[0] + ", Comment: " + row[1]);
}

조건이 둘 이상의 필드 비교하기 때문에 하이버네이트 ORM 확장은 localField 및 foreignField 형식 대신 $lookup 단계의 let 및 pipeline 형식을 사용합니다. let 옵션은 외부 컬렉션 의 각 필드 변수에 바인딩하고, pipeline 옵션은 $expr 연산자 에서 해당 변수를 조인된 컬렉션 의 필드와 비교합니다.

{
"$lookup": {
"from": "comments",
"let": {
"v0_u1_0_name": "$name",
"v1_u1_0_email": "$email"
},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{ "$eq": [ "$$v0_u1_0_name", "$name" ] },
{ "$eq": [ "$$v1_u1_0_email", "$email" ] }
]
}
}
}
],
"as": "#c1_0"
}
},
{ "$unwind": "$#c1_0" }

기본 키 가 @EmbeddedId 주석으로 선언된 복합 키인 엔터티를 조인할 수 있습니다. 복합 키를 정의하는 방법을 학습 엔티티 생성 가이드 의 복합 프라이머리 키 섹션을 참조하세요.

이 섹션의 예시에서는 publisherId 구성 요소와 bookNo 구성 요소에 키가 지정된 다음 Book 및 Review 엔터티를 사용합니다. Review 엔터티는 book 필드 에서 관련 Book 엔터티를 참조합니다.

각 엔터티는 별도의 @Embeddable 기록 에 키를 선언합니다. 키를 클래스가 아닌 기록 로 선언하면 하이버네이트 ORM이 식별자 값을 비교하는 데 필요한 equals() 및 hashCode() 메서드를 제공합니다.

다음 BookId 기록 Book 엔터티의 키를 정의합니다.

package org.example;
import jakarta.persistence.Embeddable;
@Embeddable
public record BookId(long publisherId, long bookNo) {
}

Book 엔터티의 정의는 다음과 같습니다.

package org.example;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
@Entity(name = "Book")
@Table(name = "books")
public class Book {
@EmbeddedId
private BookId id;
private String title;
public Book(BookId id, String title) {
this.id = id;
this.title = title;
}
public Book() {
}
public BookId getId() {
return id;
}
public void setId(BookId id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

다음 ReviewId 기록 Review 엔터티의 키를 정의합니다.

package org.example;
import jakarta.persistence.Embeddable;
@Embeddable
public record ReviewId(long publisherId, long bookNo) {
}

Review 엔터티의 정의는 다음과 같습니다. book 필드 연관 관계를 Book 엔티티에 매핑합니다:

package org.example;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Entity(name = "Review")
@Table(name = "reviews")
public class Review {
@EmbeddedId
private ReviewId id;
private String comment;
@ManyToOne
private Book book;
public Review(ReviewId id, Book book, String comment) {
this.id = id;
this.book = book;
this.comment = comment;
}
public Review() {
}
public ReviewId getId() {
return id;
}
public void setId(ReviewId id) {
this.id = id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
}

다음 코드는 이 섹션의 예제에서 사용하는 문서를 삽입합니다.

var blueDoor = new Book(new BookId(10, 2), "The Blue Door");
var winterLight = new Book(new BookId(10, 3), "Winter Light");
var saltAndStone = new Book(new BookId(20, 1), "Salt and Stone");
session.persist(blueDoor);
session.persist(winterLight);
session.persist(saltAndStone);
session.persist(new Review(new ReviewId(30, 7), blueDoor, "Gripping from the first page."));
session.persist(new Review(new ReviewId(30, 8), blueDoor, "A slow but rewarding read."));
session.persist(new Review(new ReviewId(20, 1), saltAndStone, "Beautifully written."));
session.persist(new Review(new ReviewId(10, 3), saltAndStone, "Dense, but worth the effort."));
var blueDoor = new Book(new BookId(10, 2), "The Blue Door");
var winterLight = new Book(new BookId(10, 3), "Winter Light");
var saltAndStone = new Book(new BookId(20, 1), "Salt and Stone");
entityManager.persist(blueDoor);
entityManager.persist(winterLight);
entityManager.persist(saltAndStone);
entityManager.persist(new Review(new ReviewId(30, 7), blueDoor, "Gripping from the first page."));
entityManager.persist(new Review(new ReviewId(30, 8), blueDoor, "A slow but rewarding read."));
entityManager.persist(new Review(new ReviewId(20, 1), saltAndStone, "Beautifully written."));
entityManager.persist(new Review(new ReviewId(10, 3), saltAndStone, "Dense, but worth the effort."));

외래 키는 한 엔터티가 참조하는 엔터티의 식별자를 저장 데 사용하는 필드 또는 필드 설정하다 입니다. 하이버네이트 ORM 확장은 외래 키 값을 사용하여 조인의 각 측면에 있는 문서를 일치시킵니다.

연관 관계가 복합 키를 가진 엔티티를 대상으로 하는 경우, Hibernate ORM 확장은 연관 관계 필드 에 외래 키를 하위 문서로 저장합니다. 하위 문서는 대상 엔터티의 _id 하위 문서 구성 요소를 미러링합니다.

Review 엔터티는 다음 형식의 문서를 생성하며, book 필드 외래 키를 하위 문서로 보유합니다.

{
"_id": { "bookNo": 7, "publisherId": 30 },
"comment": "An excellent read.",
"book": { "bookNo": 2, "publisherId": 10 }
}

하이버네이트 ORM 확장은 @ManyToOne 및 @OneToOne 연관 관계에 대해 이 레이아웃을 지원합니다. mappedBy 요소로 매핑하는 연관 관계의 반대측은 외래 키 필드를 저장하지 않습니다.

대상 엔터티에 복합 키가 있는 연결에 조인하려면 단일 필드 키가 있는 엔터티와 마찬가지로 조인 절을 사용합니다.

다음 예시 Review 엔터티의 book 필드 에서 내부 조인을 통해 리뷰하는 책의 식별자와 함께 각 검토 의 식별자를 검색합니다.

var compositeJoinResults = session.createQuery("select r.id, b.id, b.title from Review r join r.book b", Object[].class)
.getResultList();
for (var row : compositeJoinResults) {
System.out.println("Review: " + row[0] + ", Book: " + row[1] + ", Book Title: " + row[2]);
}
var compositeJoinResults = entityManager.createQuery("select r.id, b.id, b.title from Review r join r.book b", Object[].class)
.getResultList();
for (var row : compositeJoinResults) {
System.out.println("Review: " + row[0] + ", Book: " + row[1] + ", Book Title: " + row[2]);
}

Winter Light 책은 리뷰가 없기 때문에 결과에 나타나지 않습니다.

복합 키는 둘 이상의 필드 에 걸쳐 있기 때문에 하이버네이트 ORM 확장은 $lookup 단계의 let 및 pipeline 형식을 사용합니다. let 옵션은 각 외래 키 구성 요소를 변수에 바인딩합니다. pipeline 옵션은 $expr 연산자 에서 해당 변수를 대상 _id 하위 문서의 구성 요소와 비교합니다.

{
"$lookup": {
"from": "books",
"let": {
"v0_r1_0_book_publisherId": "$book.publisherId",
"v1_r1_0_book_bookNo": "$book.bookNo"
},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{ "$eq": [ "$_id.publisherId", "$$v0_r1_0_book_publisherId" ] },
{ "$eq": [ "$_id.bookNo", "$$v1_r1_0_book_bookNo" ] }
]
}
}
}
],
"as": "#b1_0"
}
},
{ "$unwind": "$#b1_0" }

이 가이드 의 조인 페치 섹션에 설명된 대로 JOIN FETCH 절을 사용하여 상위 쿼리와 동일한 쿼리 에 복합 키 연결을 로드할 수도 있습니다.

ON 조건에서는 = 연산자 사용하여 두 개의 전체 복합 식별자를 비교할 수 있습니다. 최대 절전 모드 ORM 확장은 비교를 각 주요 구성 요소에 대한 하나의 동등성 검사로 분해합니다.

왼쪽 외부 조인에서 전체 식별자 비교를 사용할 수 있으며, ON b.id = r.id AND b.title = r.comment에서와 같이 AND 연산자 사용하여 추가 조건과 결합할 수 있습니다.

다음 예시 일치하는 식별자가 있는 검토 에 각 책을 결합합니다.

var wholeIdResults = session.createQuery("select b.id, b.title, r.id from Book b join Review r on b.id = r.id", Object[].class)
.getResultList();
for (var row : wholeIdResults) {
System.out.println("Book Title: " + row[1] + ", Book: " + row[0] + ", Review: " + row[2]);
}
var wholeIdResults = entityManager.createQuery("select b.id, b.title, r.id from Book b join Review r on b.id = r.id", Object[].class)
.getResultList();
for (var row : wholeIdResults) {
System.out.println("Book Title: " + row[1] + ", Book: " + row[0] + ", Review: " + row[2]);
}

The Blue Door 식별자를 공유하는 검토 가 없기 때문에 결과에 표시되지 않습니다.

최대 절전 모드 ORM 확장은 이전 조인을 다음 단계로 변환합니다.

{
"$lookup": {
"from": "reviews",
"let": {
"v0_b1_0__id_publisherId": "$_id.publisherId",
"v1_b1_0__id_bookNo": "$_id.bookNo"
},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{ "$eq": [ "$$v0_b1_0__id_publisherId", "$_id.publisherId" ] },
{ "$eq": [ "$$v1_b1_0__id_bookNo", "$_id.bookNo" ] }
]
}
}
}
],
"as": "#r1_0"
}
},
{ "$unwind": "$#r1_0" }

복합 키 조인에는 다음과 같은 제한 사항이 있습니다.

  • 대상 엔터티에 복합 키가 있는 연결에는 @JoinColumn 또는 @JoinColumns 주석을 적용 할 수 없습니다. 하이버네이트 ORM 확장은 연관 관계 이름에서 외래 키 필드 이름을 파생하고, 이를 재정의하면 애플리케이션 시작될 때 FeatureNotSupportedException를 발생시킵니다.

  • ON 조건에서는 전체 복합 식별자를 > 또는 <와 같은 순서 연산자 와 비교할 수 없습니다. 대신 개별 주요 구성 요소를 비교하세요.

  • 두 엔터티 중 하나에 복합 키가 있는 경우 하이버네이트 ORM 확장은 @ManyToMany 연관 관계를 지원 하지 않습니다.

ON 조건은 < 및 >와 같은 범위 및 부등호 연산자가 있는 필드를 비교할 수 있습니다.

다음 예시 movies 및 comments 컬렉션을 조인하여 영화 출시하다 이후에 게시된 2015에서 개봉한 영화에 대한 댓글을 조회 .

var nonEquijoinResults = session.createQuery("select m.title, c.name from Movie m join m.comments c on c.date > m.released where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : nonEquijoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}
var nonEquijoinResults = entityManager.createQuery("select m.title, c.name from Movie m join m.comments c on c.date > m.released where m.year = :y", Object[].class)
.setParameter("y", 2015)
.getResultList();
for (var row : nonEquijoinResults) {
System.out.println("Title: " + row[0] + ", Commenter: " + row[1]);
}

최대 절전 모드 ORM 확장은 연관 관계의 키 일치와 ON 조건을 단일 $expr 연산자 로 결합하고, $lookup 단계의 let 및 pipeline 형식을 사용합니다:

{
"$lookup": {
"from": "comments",
"let": {
"v0_m1_0__id": "$_id",
"v1_m1_0_released": "$released"
},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{ "$eq": [ "$$v0_m1_0__id", "$movie_id" ] },
{ "$gt": [ "$date", "$$v1_m1_0_released" ] }
]
}
}
}
],
"as": "#c1_0"
}
},
{ "$unwind": "$#c1_0" }

MongoDB 데이터에서 다른 작업을 수행하는 방법에 대해 자세히 학습 CRUD 작업 수행 또는 쿼리 지정 가이드 참조하세요.

HQL 및 JPQL을 사용하여 쿼리를 실행 방법에 대해 자세히 학습하려면 하이버네이트 ORM 문서에서 하이버네이트 쿼리 언어 가이드 를 참조하세요.