Reputation: 688
All my hibernate entities have EAGER fetch type and I would like to override it only in some specific cases, this seems to be a bug in hibernate and was fixed in 5.4.11 (see: HHH-8776) and I am using 5.4.18.
But it does not work in my cases, maybe I am missing something. Bellow the details of the entities used in my test:
@Entity
@NamedEntityGraphs({
@NamedEntityGraph(name = "graph.AuthorBooks",
attributeNodes = @NamedAttributeNode("books")),
@NamedEntityGraph(name = "graph.AuthorBooksReviews",
attributeNodes = @NamedAttributeNode(value = "books", subgraph = "books"),
subgraphs = @NamedSubgraph(name = "books",
attributeNodes = @NamedAttributeNode("reviews")))})
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version;
@Column
private String firstName;
@Column
private String lastName;
@ManyToMany(mappedBy = "authors", fetch = FetchType.EAGER)
private Set<Book> books = new HashSet<>();
public Long getId() {
return this.id;
}
public void setId(final Long id) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion(final int version) {
this.version = version;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<Book> getBooks() {
return this.books;
}
public void setBooks(final Set<Book> books) {
this.books = books;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Author)) {
return false;
}
Author other = (Author) obj;
if (id != null) {
if (!id.equals(other.id)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public String toString() {
String result = getClass().getSimpleName() + " ";
if (firstName != null && !firstName.trim().isEmpty()) {
result += "firstName: " + firstName;
}
if (lastName != null && !lastName.trim().isEmpty()) {
result += ", lastName: " + lastName;
}
return result;
}
}
@Entity
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version;
@Column
private String title;
@Column
@Temporal(TemporalType.DATE)
private Date publishingDate;
@ManyToMany
@JoinTable(
name = "BookAuthor",
joinColumns = {
@JoinColumn(name = "bookId", referencedColumnName = "id")},
inverseJoinColumns = {
@JoinColumn(name = "authorId", referencedColumnName = "id")})
private Set<Author> authors = new HashSet<>();
@OneToMany(mappedBy = "book", fetch = FetchType.EAGER)
private Set<Review> reviews = new HashSet<>();
public Long getId() {
return this.id;
}
public void setId(final Long id) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion(final int version) {
this.version = version;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getPublishingDate() {
return publishingDate;
}
public void setPublishingDate(Date publishingDate) {
this.publishingDate = publishingDate;
}
public Set<Author> getAuthors() {
return authors;
}
public void setAuthors(Set<Author> authors) {
this.authors = authors;
}
public Set<Review> getReviews() {
return reviews;
}
public void setReviews(Set<Review> reviews) {
this.reviews = reviews;
}
@Override
public String toString() {
String result = getClass().getSimpleName() + " ";
if (title != null && !title.trim().isEmpty()) {
result += "title: " + title;
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Book)) {
return false;
}
Book other = (Book) obj;
if (id != null) {
if (!id.equals(other.id)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
}
@Entity
public class Review implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version;
@Column
private String comment;
@ManyToOne
@JoinColumn(name = "book_id")
private Book book;
public Long getId() {
return this.id;
}
public void setId(final Long id) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion(final int version) {
this.version = version;
}
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;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Review)) {
return false;
}
Review other = (Review) obj;
if (id != null) {
if (!id.equals(other.id)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public String toString() {
String result = getClass().getSimpleName() + " ";
if (comment != null && !comment.trim().isEmpty()) {
result += "comment: " + comment;
}
return result;
}
}
but when I load the authors list using:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
EntityGraph<?> graph = em.createEntityGraph("graph.AuthorBooks");
List<Author> authors = em.createQuery("SELECT DISTINCT a FROM Author a",
Author.class).setHint("javax.persistence.loadgraph", graph).getResultList();
em.getTransaction().commit();
em.close();
I can see in the logs it is also getting the reviews:
12:49:10,125 DEBUG SQL:128 - select distinct author0_.id as id1_0_0_, book2_.id as id1_1_1_, author0_.firstName as firstnam2_0_0_, author0_.lastName as lastname3_0_0_, author0_.version as version4_0_0_, book2_.publishingDate as publishi2_1_1_, book2_.title as title3_1_1_, book2_.version as version4_1_1_, books1_.authorId as authorid2_2_0__, books1_.bookId as bookid1_2_0__ from Author author0_ left outer join BookAuthor books1_ on author0_.id=books1_.authorId left outer join Book book2_ on books1_.bookId=book2_.id
12:49:10,176 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
12:49:10,183 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
12:49:10,185 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
12:49:10,188 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
12:49:10,190 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
12:49:10,192 DEBUG SQL:128 - select reviews0_.book_id as book_id5_3_0_, reviews0_.id as id1_3_0_, reviews0_.id as id1_3_1_, reviews0_.book_id as book_id5_3_1_, reviews0_.comment as comment2_3_1_, reviews0_.rating as rating3_3_1_, reviews0_.version as version4_3_1_ from Review reviews0_ where reviews0_.book_id=?
Although, in my entity graph, I am specifying to load only Authors and Books Any idea why I am running into the N+1 select issue?
Upvotes: 0
Views: 905
Reputation: 688
I found the root cause of the issue. I should use fetchgraph instead of loadgraph
EntityGraph<?> graph = em.createEntityGraph("graph.AuthorBooks");
List<Author> authors = em.createQuery("SELECT DISTINCT a FROM Author a",
Author.class).setHint("javax.persistence.fetchgraph", graph).getResultList();
Upvotes: 1