JPA Query.getResultList() - 以通用方式使用

时间:2012-12-04 10:16:07

标签: java hibernate jpa

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

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个表,我不想要创建所有类只是为了访问值。

8 个答案:

答案 0 :(得分:52)

一般规则如下:

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

因此,在您的情况下,listList<Object[]>

答案 1 :(得分:36)

由于JPA 2.0可以使用TypedQuery

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;
}

答案 2 :(得分:8)

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

答案 3 :(得分:6)

如果您需要一种更方便的方式来访问结果,可以将任意复杂的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;
}

答案 4 :(得分: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);
            }
        }
    }

答案 5 :(得分:0)

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

with all_dates as (
    select datefromparts(year(getdate()), month(getdate()), 1) dt, 0 lvl
    union all
    select dateadd(month, - lvl - 1, dt), lvl + 1
    from all_dates 
    where lvl < 3
)
select * from all_dates

This gives me following result:
2020-11-01  0
2020-10-01  1
2020-08-01  2
2020-05-01  3

I want only:
2020-11-01  0
2020-10-01  1
2020-09-01  2

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

答案 6 :(得分: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

答案 7 :(得分:0)

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