【问题标题】:How to fetch only selected attributes of an entity using Spring JPA?如何使用 Spring JPA 仅获取实体的选定属性?
【发布时间】:2016-09-07 03:17:40
【问题描述】:

我在我的项目中使用 Spring Boot (1.3.3.RELEASE) 和 Hibernate JPA。我的实体如下所示:

@Data
@NoArgsConstructor
@Entity
@Table(name = "rule")
public class RuleVO {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "name", length = 128, nullable = false, unique = true)
    private String name;

    @Column(name = "tag", length = 256)
    private String tag;

    @OneToMany(mappedBy = "rule", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RuleOutputArticleVO> outputArticles;

    @OneToMany(mappedBy = "rule", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RuleInputArticleVO> inputArticles;
}

我的存储库如下所示:

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
}

在某些情况下,我只需要获取实体 RuleVO 的 idname 属性。我怎样才能做到这一点?我发现一个通知应该可以使用 Criteria API 和 Projections 但如何?提前谢谢了。沃杰科技

【问题讨论】:

标签: spring hibernate spring-boot jpa spring-data-jpa


【解决方案1】:

您可以使用@Query 注释(HQL)来做到这一点。

请参考下面的 Spring 文档:

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query

(在spring文档中搜索@Query)

【讨论】:

    【解决方案2】:

    更新:

    正如向我指出的那样,我很懒惰,这可以很好地完成,因此我在浏览网络后更新了我的答案。

    这是一个如何获取 only id 和 only 名称的示例:

    @Repository
    public interface RuleRepository extends JpaRepository<RuleVO, Long> {
    
        @Query("SELECT r.id FROM RuleVo r where r.name = :name") 
        List<Long> findIdByName(@Param("name") String name);
    
        @Query("SELECT r.name FROM RuleVo r where r.id = :id") 
        String findNameById(@Param("id") Long id);
    }
    

    希望此更新对您有所帮助


    旧答案:

    仅检索特定属性名称/id 是不可能的,因为这不是 spring 的设计方式,也不是任何 SQL 数据库,因为您总是选择作为实体的行。

    你可以做的是查询实体中的变量,例如:

    @Repository
    public interface RuleRepository extends JpaRepository<RuleVO, Long> {
    
        public RuleVo findOneByName(String name);
        public RuleVo findOneByNameOrId(String name, Long id);
        public List<RuleVo> findAllByName(String name);
        // etc, depending on what you want
    }
    

    您可以根据需要修改这些内容。您的需求。您可以通过自动装配的存储库直接调用这些方法

    有关更多选项和示例,请参阅http://docs.spring.io/spring-data/jpa/docs/current/reference/html/ 第 5.3 节

    【讨论】:

    • 那不是真的。 Sql 是关于获取行列的。 select * from mytable 只是我们开发者的懒惰;)
    • 你是对的。好久没写查询了=Dselect field from table,瞧:列
    • 如果您在该实体中有关系则不起作用
    【解决方案3】:

    是的,您可以通过投影来实现。你有很多方法来应用它们:

    如果您可以升级到 Spring Data Hopper,它会为投影提供易于使用的支持。在reference documentation 中查看如何使用它们。

    否则,首先使用您要加载的属性创建一个 DTO,例如:

    package org.example;
    
    public class RuleProjection {
    
        private final Long id;
    
        private final String name;
    
        public RuleProjection(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Long getId() {
            return id;
        }
    
        public String getName() {
            return name;
        }
    }
    

    当然,您也可以使用 Lombok 注释。

    然后,您可以像这样在 JPQL 查询中使用:

    select new org.example.RuleProjection(rule.id, rule.name) from RuleVO rule order by rule.name
    

    如果您想避免在查询中使用 DTO 类名,另一种选择是使用 QueryDSL 实现您自己的查询方法。使用 Spring Data JPA,您必须:

    • 使用新方法创建一个新接口。例如:

      public interface RuleRepositoryCustom {
         public List<RuleProjection> findAllWithProjection();
      }
      
    • 更改您的存储库以扩展新界面。例如:

      public interface RuleRepository extends JpaRepository<RuleVO, Long>, RuleRepositoryCustom {
      ...
      
    • 使用 Spring Data JPA QueryDSL 支持创建自定义存储库的实现。您必须事先使用其 Maven 插件生成 QueryDSL 的 Q 类。例如:

      public class RuleRepositoryImpl {
      
          public List<RuleProjection> findAllWithProjection() {
              QRuleVO rule = QRuleVO.ruleVO;
              JPQLQuery query = getQueryFrom(rule);     
              query.orderBy(rule.name.asc());
              return query.list(ConstructorExpression.create(RuleProjection.class, rule.id, rule.name));
          }
      }
      

    【讨论】:

    • JPQLnew Projection(...) 对我有用。谢谢。
    【解决方案4】:

    您还可以定义自定义构造函数以使用 JPQL 获取特定列。

    例子:

    用类的完整java包路径替换{javaPackagePath} 在 JPQL 中用作构造函数。

    public class RuleVO {
       public RuleVO(Long id, String name) {
        this.id = id;
        this.name = name;
       }
    }
    
    
    @Repository
    public interface RuleRepository extends JpaRepository<RuleVO, Long> {
    
        @Query("SELECT new {javaPackagePath}.RuleVO(r.id, r.name) FROM RuleVo r where r.name = :name") 
        List<RuleVO> findIdByName(@Param("name") String name);
    }
    

    【讨论】:

    • 谢谢。此解决方案更简单,特别推荐用于关联实体。注意:虽然我们已经导入了实体,但不需要在查询注释中指定其包路径。
    • 谢谢。我尝试了我们的解决方案,但我得到了 table is not mapped 错误。我总是使用nativeQuery = true,但在你的情况下它不是nativeQuery,所以我删除了它,所以我得到了错误,比如表没有映射。在不使用 nativeQuery=true 的情况下如何工作。任何帮助...
    • @Prakash 你真的用@Entity 映射了你的表吗?看看,如果你有唯一的@Table,它只适用于本机查询。如果您同时使用 JPQL/HQL 和本机查询,则可能需要这两个注释。我可能需要有关错误和您正在使用的查询的更多信息,然后我可以提供更好的帮助。
    • @AbhilekhSingh 感谢您的回复。我解决了我的问题。实际上,在 JPQL 中,我没有引用实体名称,而是引用了表名,因为它仅适用于本机查询。当我将所有表名和列名更改为实体类名和类变量时,它开始正常工作。
    • @AbhilekhSingh 对于上述情况,您告诉创建需要从表中获取数据的不同构造函数。例如。如果我需要表中的 2 个列值,那么构造函数应该包含两个参数,依此类推。但是如果我的表中有大约 20 列,对于第一个查询,我需要名字和姓氏,所以它们都是字符串,我创建一个带有两个参数的构造函数作为字符串并获取该数据,对于下一个查询,我需要字符串下的州和城市。在下一个命令中继续.....
    【解决方案5】:
    interface IdOnly{
        String getId();
    }
    
    @Repository
    public interface RuleRepository extends JpaRepository<RuleVO, Long> {
        public List<IdOnly> findAllByName(String name);
    }
    

    我注意到这是一个非常古老的帖子,但如果有人仍在寻找答案,试试这个。它对我有用。

    【讨论】:

    • 很好奇这是否有效,因为它是一个避免编写 SQL 的答案。有空我会再来的
    • 投影工程。一个注释 - 接口必须是公开的,它必须在单独的文件中docs.spring.io/spring-data/jpa/docs/current/reference/html/…
    • 我刚刚检查过了。看起来查询选择了所有字段,所以这不是一个真正的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-04-28
    • 2018-05-10
    • 2017-04-18
    • 2016-06-30
    • 1970-01-01
    相关资源
    最近更新 更多