【问题标题】:JPA Query selecting only specific columns without using Criteria Query?JPA Query 仅选择特定列而不使用 Criteria Query?
【发布时间】:2014-09-02 20:10:00
【问题描述】:

是否可以使用JPA 查询从对象中仅选择属性A 和B,而不使用条件查询?

要选择所有属性,我只需执行以下操作:

SELECT i FROM ObjectName i WHERE i.id = 10

但是我在旧系统上有一个具有许多属性的对象,并且我想只选择几个属性,尽管我知道选择多个属性通常很快。

如果不使用条件查询,这可能吗?

【问题讨论】:

  • errm,您可以使用基于字符串的 JPQL 做任何事情,就像使用标准一样。不知道为什么会有人不这么想。
  • spring-data中的Projections可以用来实现同样的效果。

标签: java jpa jpa-2.0 jpa-2.1 criteriaquery


【解决方案1】:

是的,就像在普通 sql 中一样,您可以指定要选择的属性类型:

SELECT i.firstProperty, i.secondProperty FROM ObjectName i WHERE i.id=10

执行此查询将返回一个 Object[] 列表,其中每个数组包含一个对象的选定属性。

另一种方法是将选定的属性包装在自定义对象中并在 TypedQuery 中执行:

String query = "SELECT NEW CustomObject(i.firstProperty, i.secondProperty) FROM ObjectName i WHERE i.id=10";
TypedQuery<CustomObject> typedQuery = em.createQuery(query , CustomObject.class);
List<CustomObject> results = typedQuery.getResultList();

例子可以在this文章中找到。

2018 年 3 月 29 日更新:

@Krish:

@PatrickLeitermann 对我来说它给出了 "Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class ***" 异常。如何解决?

我猜您是在 Spring 应用程序的上下文中使用 JPA,不是吗?其他一些人正好有 the same problem,他们的解决方案是在 SELECT NEW 关键字之后添加完全限定名称(例如 com.example.CustomObject)。

也许 Spring 数据框架的内部实现只能识别使用 @Entity 注释的类或通过其简单名称在特定 orm 文件中注册的类,这导致使用此解决方法。

【讨论】:

  • 所以我需要 n 种 pojo 用于同一张桌子?满足每一种需求?我不能只使用一个对象,让一些字段为空?
  • 什么是 TypedQuery 的替代品?我需要在 jpa 1.0 上工作。那里没有输入查询。
  • @AndreaScarafoni,你可以在同一个类上有多个构造函数,并在每种情况下使用它。
  • @PatrickLeitermann 对我来说它给出了 "Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class ***" 异常。如何解决这个问题?
  • 不,当时我没有使用 Spring。
【解决方案2】:

你可以这样使用:

List<Object[]> list = em.createQuery("SELECT p.field1, p.field2 FROM Entity p").getResultList();

然后你可以迭代它:

for (Object[] obj : list){
    System.out.println(obj[0]);
    System.out.println(obj[1]);
}

但是如果您只有一个字段在查询中,您会得到一个类型列表,而不是来自 Object[]

【讨论】:

    【解决方案3】:

    Projections 可用于仅选择实体对象的特定属性(列)。

    来自文档

    Spring Data Repositories 通常在使用查询方法时返回域模型。但是,有时,您可能出于各种原因需要更改该模型的视图。在this 部分,您将学习如何定义投影以提供简化和简化的资源视图。

    只使用您想要的getters 定义一个接口。

    interface CustomObject {  
        String getA(); // Actual property name is A
        String getB(); // Actual property name is B 
    }
    

    现在从您的存储库中返回 CustomObject,如下所示:

    public interface YOU_REPOSITORY_NAME extends JpaRepository<YOUR_ENTITY, Long> {
        CustomObject findByObjectName(String name);
    }
    

    【讨论】:

      【解决方案4】:

      很好的答案!我确实有一点补充。关于这个解决方案:

      TypedQuery<CustomObject> typedQuery = em.createQuery(query , String query = "SELECT NEW CustomObject(i.firstProperty, i.secondProperty) FROM ObjectName i WHERE i.id=100";
      TypedQuery<CustomObject> typedQuery = em.createQuery(query , CustomObject.class);
      List<CustomObject> results = typedQuery.getResultList();CustomObject.class);
      

      为了防止类未找到错误,只需插入完整的包名。假设 org.company.directory 是 CustomObject 的包名:

      String query = "SELECT NEW org.company.directory.CustomObject(i.firstProperty, i.secondProperty) FROM ObjectName i WHERE i.id=10";
      TypedQuery<CustomObject> typedQuery = em.createQuery(query , CustomObject.class);
      List<CustomObject> results = typedQuery.getResultList();
      

      【讨论】:

        【解决方案5】:

        如果我正确理解了您的问题,我想您可以查看此链接http://www.javacodegeeks.com/2012/07/ultimate-jpa-queries-and-tips-list-part_09.html

        例如,他们创建了如下查询:

         select id, name, age, a.id as ADDRESS_ID, houseNumber, streetName ' +
         20' from person p join address a on a.id = p.address_id where p.id = 1'
        

        【讨论】:

          【解决方案6】:

          是的,这是可能的。您所要做的就是将您的查询更改为SELECT i.foo, i.bar FROM ObjectName i WHERE i.id = 10 之类的内容。查询结果将是Object 数组中的List。每个数组中的第一个元素是i.foo 的值,第二个元素是i.bar 的值。见JPQL reference的相关部分。

          【讨论】:

            猜你喜欢
            • 2015-02-27
            • 2012-09-19
            • 2012-09-07
            • 2013-08-25
            • 2017-05-02
            • 2022-11-18
            • 2020-10-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多