Reputation: 4938
I have entities:
@Entity
public class Author{
@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(
name = "author_book",
joinColumns = { @JoinColumn(name = "author_id") },
inverseJoinColumns = { @JoinColumn(name = "book_id") }
)
public List<Book> books;
}
@Entity
public class Book{
@ManyToMany(mappedBy = "books")
public List<Author> authors;
@OneToMany(mappedBy = "book")
public List<Fact> facts;
public Book(){}
public Book(List<Author> authors, List<Fact> facts){
this.authors = authors;
this.facts = facts;
}
}
@Entity class Fact{
@ManyToOne
@JoinColumn(name="book_id")
public Book book;
}
Book has more Authors and Authors can write more books. Every book has more facts about it and each act belongs only to one book.
Now what i want achieve is to recieve object of type Book
based on author ID. The object of type Book
should containt all authors and all facts.
I am using hibernate query for this:
List<Book> books = (List<Book>) session.createQuery("Select new Book (books.authors, books.facts ) FROM Author u JOIN u.books books JOIN books.facts WHERE u.id IN :ids ").setParameter("ids", authorId).list();
However it results in error:
Unable to locate appropriate constructor on class [Book]. Expected arguments are: java.util.Collection, java.util.Collection
I have tried to adjust constructor to take Object or Collection, and cast it by myself:
public Book(Object authors,Object facts){
this.authors = (List<Author>)authors;
this.facts = (List<Fact>)facts;
}
But this complains:
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
What is the right way to fetch entity with wanted data then? It Complains only about relations (e.g collections), i have not found any solution for this anywhere ( nor documentation for hql ).
Thanks for help!
Upvotes: 2
Views: 1316
Reputation: 36133
You cannot use the NEW operator with Entities!
This is for DTO (Data Transfer Object) projection.
In your case you don't even need the NEW because you can simply select the book which will be constructed by Hibernate using the default constructor and setting the fields.
List<Book> books =
(List<Book>) session.createQuery(
"Select books FROM Author u JOIN u.books books JOIN books.facts WHERE u.id IN :ids ")
.setParameter("ids", authorId).list();
and if you want to have the collections eager loaded use JOIN FETCH like:
List<Book> books =
(List<Book>) session.createQuery(
"Select b FROM Book b JOIN FETCH b.authors a JOIN FETCH b.facts f WHERE a.id IN :ids ")
.setParameter("ids", authorId).list();
Important notice:
Hibernate cannot fetch two Lists eagerly. There for I suggest to change the Lists to Sets:
@ManyToMany(mappedBy = "books")
public Set<Author> authors;
@OneToMany(mappedBy = "book")
public Set<Fact> facts;
Upvotes: 3