如何使用Spring JPA仅获取实体的选定属性?

时间:2016-05-11 15:42:36

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

我在我的项目中使用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的 id name 属性。我怎样才能做到这一点?我发现使用Criteria API和Projections应该可行,但是如何?提前谢谢了。 Vojtech

5 个答案:

答案 0 :(得分:12)

<强>更新

正如我所指出的那样,我很懒,而且这很可能已经完成,因此我在浏览网页后正在更新我的答案。

以下是如何 id和 名称的示例:

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

希望此更新证明有用

旧答案:

仅检索特定属性name / 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
}

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

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

答案 1 :(得分: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支持创建Custom存储库的实现。您必须先使用其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));
        }
    }
    

答案 2 :(得分:2)

您可以使用@Query annotation(HQL)来完成。

请参阅下面的Spring文档:

PHP Error logging

(在spring文档中搜索@Query)

答案 3 :(得分:2)

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

示例:

  

将{javaPackagePath}替换为该类的完整java包路径   在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);
}

答案 4 :(得分:1)

interface IdOnly{
    String getId();
}

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
    public List<IdOnly> findAllByName(String name);
}

我注意到这是一篇非常古老的文章,但是如果有人仍在寻找答案,请尝试一下。它对我有用。