0

when executing session.createQuery("from Author").list(); The associated book instance info is loaded eagerly even when relationship is marked optional=false,fetch type = lazy from Author->book as per below generated sql's. I have this relationship as one to one just for understanding purposes, and not one to many at the moment. Is it possible to make it lazy from Author-Book, if so not sure what I am missing?

Hibernate: select author0_.AUTHOR_ID as AUTHOR_I1_0_, author0_.email as email2_0_, author0_.name as name3_0_ from AUTHOR author0_

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

Hibernate: select book0_.BOOK_ID as BOOK_ID1_1_0_, book0_.AUTHOR_ID as AUTHOR_I5_1_0_, book0_.description as descript2_1_0_, book0_.PUBLISHED as PUBLISHE3_1_0_, book0_.title as title4_1_0_ from BOOK book0_ where book0_.AUTHOR_ID=?

@Entity
@BatchSize(size=3)
@Table(name = "AUTHOR")
public class Author {
    private long id;
    private String name;
    private String email;
    private Book book;


    public Author() {
    }

    public Author(String name, String email) {
        this.name = name;
        this.email = email;
    }

    @Id
    @Column(name = "AUTHOR_ID")
    @GeneratedValue
    public long getId() {
        return id;
    }

    public void setId(long 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;
    }

    @OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false,mappedBy="author")
    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }


@Entity
@BatchSize(size=3)
@Table(name = "BOOK")
public class Book {

     private long id;
        private String title;
        private String description;
        private Date publishedDate;

        private Author author;

        public Book() {
        }

        @Id
        @Column(name = "BOOK_ID")
        @GeneratedValue
        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        @Temporal(TemporalType.DATE)
        @Column(name = "PUBLISHED")
        public Date getPublishedDate() {
            return publishedDate;
        }

        public void setPublishedDate(Date publishedDate) {
            this.publishedDate = publishedDate;
        }

        @OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=false)
        @JoinColumn(name ="AUTHOR_ID",unique=true)
        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }
    }
user2221654
  • 311
  • 1
  • 7
  • 20

1 Answers1

1

You are missing that the link from Author to Book isn't the definition owner of the bidirectional association, I mean it is defined as mappedBy and the FK resides in the Book table. So when an Author is retrieved, it needs to query over the Book table to check the FK and find out if there is a book and which book is associated per Author. That is why you are seeing as many select statement on book table as Authors you have (it is known as the N+1 Query Problem).

One way to avoid it is switch the owner side of the association (defining in Author table a FK to the Book) but you will see analogous behavior quering for books.

If your concern are the collateral queries, one option is apply a fetching strategy in the query forcing to retrieve the Books associated with the Authors. The query will be something like, session.createQuery("from Author a left join fetch a.book").list();

I told you the cause and basic solution/workaround but there are more complicated options too, you could find those in stackoverflow for sure.

Guillermo
  • 1,523
  • 9
  • 19