34

我正在创建一个包含多个表的复杂查询,并且需要列出结果。通常,我使用EntityManager并将结果映射到 JPA 表示:

UserEntity user = em.find(UserEntity.class, "5");

然后我可以访问用户UserEntity类定义的所有值。但是如何访问从本机多表查询返回的字段值?我得到的是一个对象列表。到目前为止这很好,但是那个对象是什么“是”?大批?地图?收藏?...

//simpleExample
Query query = em.createNativeQuery("SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id");
List list = query.getResultList();

//do sth. with the list, for example access "something" for every result row.

我想答案很简单,但大多数例子只是展示了直接转换为 targetClass 时的用法。

PS:在示例中,我当然可以使用类映射。但在我的情况下someTable,它不是由 JPA 管理的,因此我没有实体,也没有它的类表示,而且由于我加入了 20 个表,我不想创建所有类只是为了访问这些值。

4

8 回答 8

58

一般规则如下:

  • 如果select包含单个表达式并且它是一个实体,那么结果就是那个实体
  • 如果select包含单个表达式并且它是一个原语,那么结果就是那个原语
  • 如果select包含多个表达式,则结果Object[]包含相应的原语/实体

所以,在你的情况下list是一个List<Object[]>.

于 2012-12-04T10:37:55.287 回答
53

TypedQuery由于可以使用JPA 2.0 a :

TypedQuery<SimpleEntity> q = 
        em.createQuery("select t from SimpleEntity t", SimpleEntity.class);

List<SimpleEntity> listOfSimpleEntities = q.getResultList();
for (SimpleEntity entity : listOfSimpleEntities) {
    // do something useful with entity;
}
于 2014-01-25T18:39:43.843 回答
9

如果您需要一种更方便的方法来访问结果,可以将任意复杂的 SQL 查询的结果转换为 Java 类,并且非常简单:

Query query = em.createNativeQuery("select 42 as age, 'Bob' as name from dual", 
        MyTest.class);
MyTest myTest = (MyTest) query.getResultList().get(0);
assertEquals("Bob", myTest.name);

该类需要声明为@Entity,这意味着您必须确保它具有唯一的@Id。

@Entity
class MyTest {
    @Id String name;
    int age;
}
于 2014-05-05T21:45:26.220 回答
8

上面的查询返回 Object[] 的列表。因此,如果您想从列表中获取 u.name 和 s.something,那么您需要迭代并为相应的类转换这些值。

于 2012-12-04T10:33:03.100 回答
0

这是对我有用的示例。我认为实体类中需要 put 方法将 sql 列映射到 java 类属性。

    //simpleExample
    Query query = em.createNativeQuery(
"SELECT u.name,s.something FROM user u,  someTable s WHERE s.user_id = u.id", 
NameSomething.class);
    List list = (List<NameSomething.class>) query.getResultList();

实体类:

    @Entity
    public class NameSomething {

        @Id
        private String name;

        private String something;

        // getters/setters



        /**
         * Generic put method to map JPA native Query to this object.
         *
         * @param column
         * @param value
         */
        public void put(Object column, Object value) {
            if (((String) column).equals("name")) {
                setName(String) value);
            } else if (((String) column).equals("something")) {
                setSomething((String) value);
            }
        }
    }
于 2017-01-24T15:07:35.790 回答
0

我有同样的问题,我发现一个简单的解决方案是:

List<Object[]> results = query.getResultList();
for (Object[] result: results) {
    SomeClass something = (SomeClass)result[1];
    something.doSomething;
}

我知道这绝对不是最优雅的解决方案,也不是最佳实践,但它确实有效,至少对我而言。

于 2020-11-19T00:41:00.083 回答
0

如果您创建一个具有所有必需属性的 bean 并使用 Java 8+ 流转换结果会怎样?

像这样:

public class Something {

    private String name;
    private String something;

    // getters and setters
}

进而:

import javax.persistence.Query;

...

Query query = em.createNativeQuery("SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id", Something.class);
List<?> list = query.getResultList();

return list
         .stream()
         .map(item -> item instanceof Something ? (Something) item : null)
         .collect(Collectors.toList());

这样,您无需返回List<Object[]>或隐藏警告@SuppressWarnings("unchecked")

附言:

1 - 我知道这篇文章很老了。但是...我在 2021 年在这里,所以其他人也会来这里 =)

2 - 这是错误的还是不好的做法?让我知道 :D

于 2021-04-26T22:28:10.323 回答
0

您还可以将您的休眠更新到高于 5.4.30.final 的版本

于 2021-05-18T22:59:16.323 回答