简体   繁体   中英

JPQL many to many - in clause

Can you please help me find out what is wrong with the following JPQL query. It should filter books by their genres.

Query has additional OR conditions which I have removed due to better readability (with or without the other conditions the error is the same).

@Query("SELECT b FROM Book b WHERE " + 
        "b in (select distinct b1 FROM Book b1 inner join b1.genres genre where genre in :genres)")
List<Book> searchBooks(@Param("genres") List<Genre> genres);

Following is the stacktrace:

Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: , near line 1, column 197 [select count(b) FROM *.domain.Book AS b WHERE b.id = (select distinct b1.id FROM *.domain.Book b1 inner join b1.genres genre where genre in :genres_0_, :genres_1_)]

Relation between Book and Genre classes is ManyToMany undirectional.

    @ManyToMany
    @JoinTable(name = "books_genres",
                 joinColumns = @JoinColumn(name = "BOOK_ID"),
                 inverseJoinColumns = @JoinColumn(name = "GENRE_ID"))
    private List<Genre> genres;

I have checked the subquery separately and it works:

@Query("select distinct b1 FROM Book b1 inner join b1.genres genre where genre in :genres")
    List<Book> searchBooksByGenre(@Param("genres") List<Genre> genres);

Is it possible at all to use the subquery in this way?

Your query with nested select is OK, but you must use MEMBER keyword instead of IN when you want to search in collection of entities.

Here is a good explanation of MEMBER and IN : https://stackoverflow.com/a/9820394/784594 . Also have a look at here: http://www.objectdb.com/java/jpa/query/jpql/collection#NOT_MEMBER_OF_

However , even if the documentation says that IN keyword is used when you compare according a list passed as a parameter, hibernate seems to behave oddly if you pass list of entities instead of list of primitive values. I came accross this recently and using MEMBER fixed the problem . I am not sure if this is a hibernate bug or whether all other providers behave the same way.

In the documentation to ObjectDB, you may read that it treats IN and MEMBER in the same way. In my opinion, there is no reason why there should be 2 keywords if JPA provider should have enough information to interpret the query even if IN was used in both cases.

Unfortunately I had further issues with memberOf, pertaining to data format, when passing a list of genres and check if they exist in book genre list, query would fail with a data format exception.

@Query("SELECT b FROM Book b WHERE " +
        ":genres MEMBER OF b.genres")

with @Param("genres") List<Genre> genres

would cause the following (1 and 4 are ids of the Genre objects in genres parameter passed to the query):

Caused by: org.h2.jdbc.JdbcSQLException: Data conversion error converting "(1, 4)"; SQL statement:

I have abandoned the mentioned solution and managed to solve the issue using the "subquery" as a normal query and then continued adding conditions to the query.

So final solution is the following:

@Query("select distinct b1 FROM Book b1 inner join b1.genres genre where genre in :genres AND (---additional querys---)")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM