错误:无法为具有多个返回的查询创建TypedQuery

use*_*944 22 java sql postgresql jpa

我尝试用java和jpa做函数searchBook.我有2个课程,分别是媒体和书.本书扩展了媒体.我将数据保存在不同的表中.我尝试从下面的查询中选择数据:

TypedQuery<Media> query = em.createQuery(
                "SELECT m.title, b.isbn, b.authors"
                        + " FROM Book b, Media m" + " WHERE b.isbn = :isbn"
                        + " OR lower(m.title) LIKE :title"
                        + " OR b.authors LIKE :authors", Media.class);
        query.setParameter("isbn", book.getisbn());
        query.setParameter("title", "%" + book.getTitle().toLowerCase()
                + "%");
        query.setParameter("authors", "%" + book.getAuthors() + "%");
        bookList = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

但是我得到了错误:

java.lang.IllegalArgumentException:无法为具有多个返回的查询创建TypedQuery

这是我第一次使用JPA.我找不到错误.

Nay*_*kar 48

作为一种变通方法,要获取由其他实体属性组成的实体,您可以在查询中创建它,为其提供构造函数.

查询:

TypedQuery<Media> query = em.createQuery("SELECT NEW package_name.Media(m.title, b.isbn, b.authors)"
+ " FROM Book b, Media m" 
+ " WHERE b.isbn = :isbn"                         
+ " OR lower(m.title) LIKE :title"                         
+ " OR b.authors LIKE :authors", Media.class); 
Run Code Online (Sandbox Code Playgroud)

实体 :

public Media(String title, int isbn, String author){

    //-- Setting appropriate values
}
Run Code Online (Sandbox Code Playgroud)

我提供了示例,相应地更改了构造函数的数据类型.


JB *_*zet 34

如果没有详细说明如何MediaBook应该建模,我至少会解释为什么你会得到这个例外.

你在做:

em.createQuery(someJPQL, Media.class);
Run Code Online (Sandbox Code Playgroud)

这意味着:使用创建查询someJPQL,此查询将返回Media实体的实例.

但你的JPQL是:

SELECT m.title, b.isbn, b.authors ...
Run Code Online (Sandbox Code Playgroud)

因此查询不返回Media类型的实体.它返回来自两个不同实体的三个字段.您的JPA引擎无法从这3列神奇地创建Media实例.如果查询如下所示,则查询将返回Media的实例:

select m from Media m ...
Run Code Online (Sandbox Code Playgroud)


Dav*_*Mar 5

如果您仍然想使用,TypedQuery您可以将结果类型更改为Object[].

List<Object[]> results = entityManager
    .createQuery("SELECT m.title, b.isbn, b.authors ...", Object[].class)
    .getResultList();
Run Code Online (Sandbox Code Playgroud)

每个Object[]List代表一行数据。它包含按在查询中选择的顺序为该行选择的值。元素 0 是标题,元素 1 是 ISBN,元素 2 是作者。如果您想以有意义的方式使用它们,您可能需要强制转换这些值。由于字段值来自两个不同的表,您可以将它们存储在某种容器对象中。

List<MediaContainer> mediaList = new ArrayList<>();

for (Object[] row : results) {
    MediaContainer container = new MediaContainer();
    container.setTitle((String) row[0]);
    container.setIsbn((int) row[1]);
    container.setAuthors((String) row[2]);

    mediaList.add(container);
}
Run Code Online (Sandbox Code Playgroud)