使用JPA注释在查询中强制联接



我很难强迫Hibernate在获取数据时使用两个表之间的联接。我们有一个大型父表和一个大型子表,由多列连接(没有单一的ID列(。当我们获取父记录时,Hibernate急切地获取子记录,但它使用单独的查询来完成,每个父记录一个查询。与只有一个带有联接的查询相比,这似乎非常慢

但是,如何让Hibernate进行连接呢?

以下是实体(这只是一个匿名示例(:

@Entity
@Table(name = "BOOKS")
public class Book
{
@EmbeddedId
private BookID id;
@Column(name = "DESCRIPTION")
private String description;
@Column(name = "PUBLISH_DATE")
private Date publishDate;
@OneToMany(mappedBy = "book", fetch = EAGER, cascade = ALL, orphanRemoval = true)
private List<BookReview> reviews;
}
@Entity
@Table(name = "BOOK_REVIEWS")
public class BookReview
{
@EmbeddedId
private BookReviewID id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "TITLE", referencedColumnName = "TITLE"),
@JoinColumn(name = "AUTHOR_FIRST_NAME", referencedColumnName = "AUTHOR_FIRST_NAME"),
@JoinColumn(name = "AUTHOR_LAST_NAME", referencedColumnName = "AUTHOR_LAST_NAME")
})
private Book book;
@Column(name = "UPDATE_DATE")
private Date updateDate;
}

以及它们的嵌入式密钥:

@Embeddable
public class BookID
{
@Column(name = "TITLE")
private String title;
@Column(name = "AUTHOR_FIRST_NAME")
private String authorFirstName;

@Column(name = "AUTHOR_LAST_NAME")
private String authorLastName;
}
@Embeddable
public class BookReviewID extends BookID
{
@Column(name = "USERNAME")
private String userName;
}

当我对BOOK中的所有记录运行查询时(使用entityManager.createQuery("from Book")(,它会对BOOK表运行查询以获取所有记录,然后对每个记录的评论进行单独的查询。与其对每本书的每组评论进行单独的查询,不如一开始只做一个left outer join来获取它们。

这甚至可以通过注释实现吗?或者我必须使用CriteriaBuilder或查询语言吗?

我应该注意的是,添加@Fetch(FetchMode.JOIN)并不会改变它似乎在做什么。

Hibernate文档强烈建议使用fetch = FetchType.LAZY而不是fetch = FetchType.EAGER:

如果您忘记了JOIN FETCH所有EAGER关联,Hibernate将为每一个关联发出一个辅助选择,这反过来会导致N+1查询问题。

出于这个原因,你应该更喜欢LAZY协会。

因此,我建议您更正此关联:

@OneToMany(mappedBy = "book", fetch = EAGER, cascade = ALL, orphanRemoval = true)
private List<BookReview> reviews;

到此:

@OneToMany(mappedBy = "book", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<BookReview> reviews;

然后通过在HQL中使用CCD_ 10来覆盖加入的关联的惰性,如下所示:

entityManager.createQuery(
"select b from Book b join fetch b.reviews"
)

对于@Fetch(FetchMode.JOIN),如文件中所述:

我们之所以不使用JPQL查询来获取多个实体,是因为FetchMode.JOIN策略将被查询获取指令覆盖

因此,当实体通过其标识符或natural-id直接提取时,FetchMode.JOIN非常有用

此外,FetchMode.JOIN充当FetchType.EAGER策略。即使我们将关联标记为FetchType.LAZYFetchMode.JOIN也会急切地加载该关联。

因此,FetchMode.JOIN将仅适用于以下直接获取:

Book book = entityManager.find(Book.class, new BookID(...));

最新更新