๐ ํ๊ฒฝ
- QueryDSL 5.0.0
- Spring Data JPA 3.1.2
๐ JOIN ์ข ๋ฅ
1. INNER JOIN
JOIN ๋นํ๋ ํ ์ด๋ธ์ A, JOIN์ ๊ฑฐ๋ ํ ์ด๋ธ์ B๋ผ๊ณ ํ ๋, A์ B ํ ์ด๋ธ ๋ชจ๋ JOIN์ ํ๋ ค๋ ๋์ Key ์ปฌ๋ผ์ ๋ํด ๊ฐ์ด ์กด์ฌํ๋ ๊ฒฝ์ฐ๋ง JOIN์ ํ๋ ๊ฒ์ INNER JOIN์ด๋ผ๊ณ ํฉ๋๋ค.
queryDSL์์ Inner join์ ์ฐ๋ ๋ฐฉ๋ฒ์ ๊ฐ๋จํฉ๋๋ค.
queryFactory์์ select์ from์ ์ดํ์ join ๋ฉ์๋๋ฅผ ํฌํจํ๋ฉด ๋ฉ๋๋ค.
์๋๋ ์ฝ๋ ์์์ ๋๋ค.
@Entity
@Getter
@Table(name = "neo_starpage")
public class StarPage {
@EmbeddedId
@AttributeOverride(name = "value", column = @Column(name = "star_page_id"))
private StarPageId starPageId;
// ์คํ ํ์ด์ง ์ ๋ณด
@Embedded
private StarPageInfo information;
// ์คํ ํ์ด์ง ์์ ๊ฐ๋ฅ ์ด๋๋ฏผ
@ElementCollection
@CollectionTable(name = "neo_starpage_admin", joinColumns = @JoinColumn(name = "star_page_id"))
private Set<NEOMember> admins = new HashSet<>();
// ์คํํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๋ ๋ ์ด์์ ๊ตฌ์ฑ์์
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
@JoinColumn(name = "star_page_id")
@OrderColumn(name = "layout_order")
private List<StarPageLayoutLine> layoutLines = new ArrayList<>();
}
@Getter
@Entity
@Table(name = "neo_starpage_layout")
@DiscriminatorColumn(name = "unique_or_categorical")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class StarPageLayoutLine {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long layoutId;
@Embedded
@AttributeOverride(name = "value", column = @Column(name = "layout_title"))
private LayoutTitle layoutTitle;
@Column(name = "layout_type")
@Enumerated(EnumType.STRING)
private StarPageLayoutType type;
public StarPageLayoutLine(LayoutTitle layoutTitle, StarPageLayoutType type){
this.layoutTitle = layoutTitle;
this.type = type;
}
public abstract boolean isRemoveAble();
public abstract List<? extends StarPageHeadLine> getHeadLineByLayout(StarPageId starPageId, StarPageRepository repo);
}
@Override
public Optional<StarPage> findStarPageWithLayout(StarPageId starPageId) {
return Optional.ofNullable(queryFactory
.selectFrom(starPage)
.innerJoin(starPage.layoutLines, starPageLayoutLine).fetchJoin()
.where(starPage.starPageId.eq(starPageId))
.fetchOne());
}
์ queryDSL ์ฝ๋์ starPage์ starPageLayoutLine์ Qํด๋์ค ๊ฐ์ฒด์ ๋๋ค.
inner join์ ํตํด ์คํํ์ด์ง์ ๋ ์ด์์ ํ ์ด๋ธ์ INNER JOINํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
INNER JOIN์ด๊ธฐ ๋๋ฌธ์ ๋ ์ด์์ ํ ์ด๋ธ์ ํน์ ์คํํ์ด์ง ์์ด๋๊ฐ ์๋ค๋ฉด, ํด๋น ์คํํ์ด์ง ์์ด๋์ ๋ํ ์คํํ์ด์ง ํ ์ด๋ธ์ ๋ด์ฉ๋ ํฌํจ๋์ง ์์ต๋๋ค.
2. LEFT JOIN, RIGHT JOIN
Left Join์ JOIN ๋นํ๋ ํ ์ด๋ธ (from ์ )์ ๋ชจ๋ ํ ์ด๋ธ์ ๋ํด JOIN ํ๋ ค๋ ๋์ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ฅผ ํฉ์น๋ JOIN์ ๋๋ค.
๋ง์ฝ Right Table์ Left Table์ ํค ๊ฐ์ ๊ฐ์ง๊ณ ์์ง ์๋ค๋ฉด, JOIN๋ ํ ์ด๋ธ์์๋ ํด๋น ๋ถ๋ถ์ NULL์ธ ์ํ๋ก JOIN ๋ฉ๋๋ค.
Right Join์ JOIN ํ๋ ค๋ ๋์ ํ ์ด๋ธ์ ๋ํด JOIN ๋นํ๋ ๋์ ํ ์ด๋ธ(from)์ ๋ฐ์ดํฐ๋ฅผ ํฉ์น๋ JOIN์ ๋๋ค.
๋ง์ฝ Left Table์ Right Table์ ํค ๊ฐ์ ๊ฐ์ง๊ณ ์์ง ์๋ค๋ฉด, JOIN๋ ํ ์ด๋ธ์์๋ ํด๋น ๋ถ๋ถ์ NULL์ธ ์ํ๋ก JOIN ๋ฉ๋๋ค.
QueryDSL์์๋ .leftJoin(), .rightJoin()์ ํตํด ๊ตฌํํ ์ ์์ต๋๋ค.
์๋๋ .leftJoin()์ ์ฌ์ฉํ ์์์ ๋๋ค.
@Override
public List<RepresentativeArticleHeadLine> searchHeadLineByStarPageIdAndLimit(StarPageId id, long limit) {
// ์นดํ
๊ณ ๋ฆฌ๋ช
, ์ ๋ชฉ, ์์ฑ์, ์ข์์ ์, ๊ธ ๋ด์ฉ ํ์ธ API Path, ๋ํ ์ด๋ฏธ์ง DTO์ ๋ด๊ธฐ.
return queryFactory
.select(
Projections.constructor(
RepresentativeArticleHeadLine.class,
starPagePost.id, starPagePost.likeCount, starPagePost.author.authorName,
category.categoryInformation.categoryTitle, starPagePost.postType.stringValue(), starPagePost.title,
albumPost.image.path.coalesce(commonPost.representativeImage).as("representativeImage"),
Expressions.asString("๋ฒ ์คํธ ํฌ ๊ฒ์๋ฌผ").as("tapName")
))
.from(starPagePost)
.innerJoin(category).on(starPagePost.categoryId.eq(category.categoryId))
.leftJoin(albumPost).on(eqPostId(albumPost.id))
.leftJoin(commonPost).on(eqPostId(commonPost.id))
.leftJoin(starPage).on(starPage.starPageId.eq(category.starPageId))
.where(
eqStarPageId(id),
neHostEmail(starPage.information.host.email),
eqPostStatus(PostStatus.MAIN_EXPOSED)
)
.orderBy(starPagePost.exposureAt.desc())
.limit(limit)
.fetch();
}
starPagePost๋ common, album, vote, goldbalance ์ด 4๊ฐ์ ์ ํ์ผ๋ก ๋๋ ์ ธ์๊ณ , JOIN ํ ์ด๋ธ ์ ๋ต์ผ๋ก ์์ํ๋ ๋ถ๋ชจ ์ํฐํฐ์ ๋๋ค.
์คํํ์ด์ง ํฌ์คํธ๋ค ์ค์ album, common๋ง ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ด๋ฏธ์ง๋ฅผ ํฌํจํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋จธ์ง ํฌ์คํธ ์ ํ์ ๋ํด albumPost, commonPost๋ฅผ innerJoin์ ํ๋ค๋ฉด vote, goldbalance์ธ ํฌ์คํธ๋ค์ ํ ์ด๋ธ์์ ๋น ์ง๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ leftJoin์ ํ์ฉํ ๋ชจ์ต์ ๋๋ค.
3. Fetch JOIN
JPQL์ Fetch JOIN์ ๊ด๊ณํ ์ํฐํฐ์์ ์ฐ๊ด๋ ์ํฐํฐ๋ค์ ํจ๊ป ๋ก๋ฉํ๋ ๋ฐฉ๋ฒ์ ์ง์ ํ๋ ๊ธฐ๋ฅ์ ๋๋ค. Fetch JOIN์ ์ฌ์ฉํ๋ฉด ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ์ง์ฐ ๋ก๋ฉ(Lazy Loading)์ด ์๋๋ผ ์ฆ์ ๋ก๋ฉ(Eager Loading)ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด N+1 ์ฟผ๋ฆฌ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ณ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
JPA๋ฅผ ์ฌ์ฉํ๋ฉด์ ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ Entity, ElementCollection์ ๋ํด JOIN์ ํตํด ํ ๋ฒ์ ๊ฐ์ ธ์ค๊ธธ ์ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ฐ Fetch JOIN์ ํตํด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
QueryDSL-JPA๋ JPQL์ Typesafeํ๊ฒ ์์ฑํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ฏ๋ก, QueryDSL-JPA์์๋ FetchJoin์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฌ์ฉ๋ฒ์ ๋จ์ํ๊ฒ .innerJoin(), .leftJoin(), .rightJoin() ๋ค์ .fetchJoin()์ ๋ถ์ฌ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
.innerJoin(starPage.layoutLines, starPageLayoutLine).fetchJoin()
์๋๋ FetchJoin์ ํ ๊ฒฝ์ฐ์ ํ์ง ์์ ๊ฒฝ์ฐ์ ๋ํ ๊ฒฐ๊ณผ์ ๋๋ค.
- FetchJoin์ ํ ๊ฒฝ์ฐ์๋ ์ฐ๊ด๊ด๊ณ์ ์ํ ์ํฐํฐ์ ๊ฐ๊น์ง ํ ๋ฒ์ SELECTํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ฆ์ ๋ก๋ฉ์ ํตํด layout์ ์ฌ์ฉํ๋๋ผ๋ ์ถ๊ฐ ์ฟผ๋ฆฌ ์์ด ๋ฐ๋ก ์ฌ์ฉ๊ฐ๋ฅํฉ๋๋ค.
- FetchJoin์ ํ์ง ์์ ๊ฒฝ์ฐ์๋ JOIN์ ์ ๋์์ง๋ง, SELECT์๋ layout์ ๋ํ(์ฐ๊ด๊ด๊ณ ์ํฐํฐ) ์ ๋ณด๋ ๊ฐ์ ธ์ค์ง ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ์๋ ์คํํ์ด์ง์์ ๋ ์ด์์์ ์ฌ์ฉํ๋ค๋ฉด ์ถ๊ฐ ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
์ฐธ๊ณ ๋ก ์กฐํ๋ฅผ ์ํด ์ํฐํฐ๊ฐ ์๋ 'DTO'๋ฅผ SELECT ํ๋ค๋ฉด, FetchJoin์ ๋น์ฐํ๊ฒ๋ ํ์ ์์ต๋๋ค.
FetchJoin์ JPQL์ Fetch JOIN์ ๊ด๊ณํ ์ํฐํฐ์์ ์ฐ๊ด๋ ์ํฐํฐ๋ค์ ํจ๊ป ๋ก๋ฉํ๋ ๋ฐฉ๋ฒ์ ์ง์ ํ๋ ๊ธฐ๋ฅ์ ๋๋ค. ๋ฐ๋ผ์ DTO๋ ์ํฐํฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฉ๋๋ค.
query specified join fetching, but the owner of the fetched association was not present in the select list
DTO๋ ์ผ๋ฐ์ ์ธ JOIN๋ง ์งํํ๋ฉด ๋ฉ๋๋ค.
+ ์ํฐํฐ๋ฅผ ์ฌ์ฉํ ๋ JOIN์ ํ๋ฉด ๋ฌด์กฐ๊ฑด ์ฆ์๋ก๋ฉ์ ์ํ JOIN์ธ๊ฐ? ๋ฌด์กฐ๊ฑด FetchJoin์ธ๊ฐ?
์ฆ์๋ก๋ฉ์ ์ํ JOIN์ด๋ผ๋ฉด FetchJoin์ ์ฐ๋ฉด ๋์ง๋ง,
์ฆ์๋ก๋ฉ์ ์ํ๋ ๊ฒ์ด ์๋๋ผ ์ฐ๊ด๋ ์ํฐํฐ์ ๋ํ '์กฐ๊ฑด'๋ง ํ์ํ ๊ฒฝ์ฐ์๋ ์ผ๋ฐ ์กฐ์ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
4. CROSS JOIN (๋ช ์์ JOIN์ ํตํด CROSS JOIN์ ์ํ ์ฑ๋ฅ ์ ํ ์ ๊ฑฐ)
๋ช ์์ ์ธ JOIN์ ์ฌ์ฉํ๋ฉด CROSS JOIN์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ ์ํฐํฐ์์ ๋ณ๋ค๋ฅธ JOIN ์์ด WHERE ์กฐ๊ฑด ์ ์์ ์ฐ๊ด๊ด๊ณ ์ํฐํฐ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํ์ด๋ฒ๋ค์ดํธ์์ CROSS JOIN์ ์๋ฌต์ ์ผ๋ก ์ ํํ๋ ๊ฒฝํฅ์ด ์์ต๋๋ค.
๋ฐ๋ผ์ QueryDSL์ ์์ฑํ ๋ ๋ช ์์ ์ผ๋ก JOIN๋ฌธ์ ์์ฑํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๐ JOIN ๋์์ ๋ฐ๋ฅธ ์ ๋ฆฌ
1. ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ Entity๊ฐ JOINํ๊ธฐ
๐ค StarPage Entity
@Entity
@Getter
@Table(name = "neo_starpage")
public class StarPage {
@EmbeddedId
@AttributeOverride(name = "value", column = @Column(name = "star_page_id"))
private StarPageId starPageId;
// ์คํ ํ์ด์ง ์ ๋ณด
@Embedded
private StarPageInfo information;
// ์คํ ํ์ด์ง ์์ ๊ฐ๋ฅ ์ด๋๋ฏผ
@ElementCollection
@CollectionTable(name = "neo_starpage_admin", joinColumns = @JoinColumn(name = "star_page_id"))
private Set<NEOMember> admins = new HashSet<>();
// ์คํํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๋ ๋ ์ด์์ ๊ตฌ์ฑ์์
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
@JoinColumn(name = "star_page_id")
@OrderColumn(name = "layout_order")
private List<StarPageLayoutLine> layoutLines = new ArrayList<>();
}
์์ ์ฝ๋์์, StarPage์ StarPageLayoutLine์ 1:N์ ์ฐ๊ด๊ด๊ณ(@OneToMany)๋ฅผ ๊ฐ์ง๋๋ค. ์ด ๋ ์ํฐํฐ๋ฅผ ํ ๋ฒ์ InnerJoinํด ๊ฐ์ ธ์ค๋ ค๋ฉด, ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
@Override
public Optional<StarPage> findStarPageWithLayout(StarPageId starPageId) {
return Optional.ofNullable(queryFactory
.selectFrom(starPage)
.innerJoin(starPage.layoutLines, starPageLayoutLine).fetchJoin()
.where(starPage.starPageId.eq(starPageId))
.fetchOne());
}
// .innerJoin(์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ ํ๋, ์ฐ๊ด๊ด๊ณ ๋์ Qํด๋์ค).fetchJoin()
.innerJoin(starPage.layoutLines, starPageLayoutLine).fetchJoin()
์์ ๊ฐ์ ๋ฌธ๋ฒ์ผ๋ก Join์ ํ๋ค๋ฉด, JoinColumn์ ๊ธฐ๋ฐ์ผ๋ก ๋ ํ ์ด๋ธ์ Joinํด ์คํํ์ด์ง ์ํฐํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ์ธ๊ธํ FetchJoin์ ์ฌ์ฉํด ๋ ์ด์์๋ ํจ๊ป ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค. ์๋์ฒ๋ผ์.
2. ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ Entity๊ฐ JOINํ๊ธฐ (๋ค๋ฅธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ID๋ฅผ ์์งํ ๊ฒฝ์ฐ ๋ฑ.)
ํ์ง๋ง ์ฐ๋ฆฌ๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง ์ํฐํฐ์ ๋ํด์๋ง JOIN์ ํ์ง ์์ต๋๋ค.
DDD START!๋ผ๋ ์ฑ ์์๋ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ฐ๊ด๊ด๊ณ ๋จ์ฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ๋ํ ID๋ฅผ ํฌํจํ๋ ๋ฐฉ์์ ์ ์ํฉ๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์๋ JPA ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ , ์๋ ํ ์ด๋ธ์ ๋ํ ID๋ง์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ ํ์์ผ๋ก๋ ํ ์ด๋ธ ์กฐ์ธ์ ์งํํ ์ ์์ต๋๋ค.
QueryDSL์ ์ฌ์ฉํ๋ฉด .on ๋ฉ์๋์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
์๋๋ ์์ ์ฝ๋์ ๋๋ค.
๐ค StarPagePost Entity
@Entity
@Table(name = "star_page_post")
@Inheritance(strategy = InheritanceType.JOINED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class StarPagePost extends NEOTimeDefaultEntity {
@Id
@Column(name = "post_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
@Column(name = "category_id")
private CategoryId categoryId;
@Column(name = "post_title")
private String title;
@Embedded
@Column(name = "author_name")
private Author author;
@Column(name = "status")
@Convert(converter = PostStatusConverter.class)
private PostStatus status;
@Column(name = "like_count", nullable = false)
private int likeCount;
@Column(name = "host_heart", nullable = false)
private boolean hostHeart;
@Column(name = "exposure_at")
private LocalDateTime exposureAt;
@Column(name = "post_type", nullable = false)
@Convert(converter = PostTypeConverter.class)
private PostType postType;
@ElementCollection
@CollectionTable(name = "star_page_post_like", joinColumns = @JoinColumn(name = "post_id"))
private Set<PostLike> likes = new HashSet<>();
}
๐ค Category Entity
@Entity
@Table(name = "neo_starpage_category")
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Category {
@Getter
@EmbeddedId
@Column(name = "category_id")
private CategoryId categoryId;
@Getter
@Column(name = "starpage_id")
private StarPageId starPageId;
@Column(name = "category_status")
@Convert(converter = CategoryStatusConverter.class)
private CategoryStatus categoryStatus;
@Getter
@Column(name = "content_type")
@Convert(converter = ContentTypeConverter.class)
private ContentType contentType;
@Getter
@Embedded
@AttributeOverride(name = "categoryTitle", column = @Column(name = "title"))
private CategoryInformation categoryInformation;
@Embedded
private ContentRestriction restriction;
}
StarPagePost ์ํฐํฐ๋ Category์ ID๋ฅผ ์์งํ๊ณ ์์ต๋๋ค. JPA ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฌ์ฉํ์๋ค๋ฉด, Category : StarPagePost๋ 1:N์ ๊ด๊ณ๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค.
์๋๋ ๋ฉ์ธํ๋ฉด์ ๋ ธ์ถ๋ ํค๋๋ผ์ธ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ฝ์์ค๋ QueryDSL ์ฝ๋์ธ๋ฐ์,
๋๋จธ์ง ์ฝ๋๋ ๋ณด์ง ์๊ณ ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ Entity๊ฐ JOINํ๋ ๋ฐฉ๋ฒ์ ์๊ธฐ ์ํ ์๋ฃ์ด๋ innerJoin๊ณผ leftJoin๋ง ๋ณด๋ฉด ๋ฉ๋๋ค.
๐ค ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ Entity๊ฐ Joinํ๋ QueryDSL ์์ ์ฝ๋
@Override
public List<RepresentativeArticleHeadLine> searchHeadLineByStarPageIdAndLimit(StarPageId id, long limit) {
// ์นดํ
๊ณ ๋ฆฌ๋ช
, ์ ๋ชฉ, ์์ฑ์, ์ข์์ ์, ๊ธ ๋ด์ฉ ํ์ธ API Path, ๋ํ ์ด๋ฏธ์ง DTO์ ๋ด๊ธฐ.
return queryFactory
.select(
Projections.constructor(
RepresentativeArticleHeadLine.class,
starPagePost.id, starPagePost.likeCount, starPagePost.author.authorName,
category.categoryInformation.categoryTitle, starPagePost.postType.stringValue(), starPagePost.title,
albumPost.image.path.coalesce(commonPost.representativeImage).as("representativeImage"),
Expressions.asString("๋ฒ ์คํธ ํฌ ๊ฒ์๋ฌผ").as("tapName")
))
.from(starPagePost)
.innerJoin(category).on(starPagePost.categoryId.eq(category.categoryId))
.leftJoin(albumPost).on(eqPostId(albumPost.id))
.leftJoin(commonPost).on(eqPostId(commonPost.id))
.leftJoin(starPage).on(starPage.starPageId.eq(category.starPageId))
.where(
eqStarPageId(id),
neHostEmail(starPage.information.host.email),
eqPostStatus(PostStatus.MAIN_EXPOSED)
)
.orderBy(starPagePost.exposureAt.desc())
.limit(limit)
.fetch();
}
// .innerJoin(Joinํ๊ณ ์ ํ๋ ์ํฐํฐ Q๊ฐ์ฒด).on(์กฐ๊ฑด(์์งํ๊ณ ์๋ ์์ด๋์, Joinํ๊ณ ์ ํ๋ ์ํฐํฐ์ ์์ด๋๊ฐ ๋์ผํ๋ค๋ ์กฐ๊ฑด))
.innerJoin(category).on(starPagePost.categoryId.eq(category.categoryId))
์์ ๊ฐ์ด Join๊ณผ on ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ฐ๊ด๊ด๊ณ๊ฐ ์๋ ๋ ์ํฐํฐ๊ฐ Join๋ ๊ฐ๋ฅํฉ๋๋ค.
3. Entity์ ์ปฌ๋ ์ VO(Element Collection)๊ฐ JOINํ๊ธฐ
์ด์ ๊ธ์์ ์์ฑํ๋ฏ์ด, ๋ณ๋ค๋ฅธ .on() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ํด๋น Qํ์ ๊ฐ์ฒด์์ ์ปฌ๋ ์ VO๋ฅผ ์ ํํ๋ฉด JOIN์ ํ ์ ์์ต๋๋ค.
@Override
public Optional<StarPage> findStarPageWithInformation(StarPageId starPageId) {
return Optional.ofNullable(queryFactory.
selectFrom(starPage)
.innerJoin(starPage.information.host.starTypes).fetchJoin()
.innerJoin(starPage.information.host.snsLines).fetchJoin()
.where(starPage.starPageId.eq(starPageId))
.fetchOne());
}
์์ ์ฝ๋์์ starPage๋ ์ ๊ทธ๋ฆฌ๊ฑฐํธ ๋ฃจํธ์ธ ์ํฐํฐ์ด๋ฉฐ, starPage.information.host.starTypes๋ ์ปฌ๋ ์ ๊ฐ ๊ฐ์ฒด์ ๋๋ค. ๋ณ๋ค๋ฅธ ๋ฐฉ๋ฒ ์์ด Qํ์ ์ ์ปฌ๋ ์ ๊ฐ ๊ฐ์ฒด๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ์๋์ผ๋ก ์ฐ๊ณ๋ ์ํฐํฐ์ ID๋ฅผ ๊ธฐ์ค์ผ๋ก JOIN๋์ด SELECTํ๋ ๋ชจ์ต์ ๋ณผ ์ ์์ต๋๋ค.