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

Voj*_*ech 14 spring hibernate jpa spring-data-jpa spring-boot

我在我的项目中使用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;
}
Run Code Online (Sandbox Code Playgroud)

我的存储库看起来像这样:

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,我只需要获取实体RuleVO的idname属性.我怎样才能做到这一点?我发现使用Criteria API和Projections应该可行但是如何?提前谢谢了.Vojtech

Roe*_*erg 14

更新:

正如已经向我指出的那样,我很懒,这很可能已经完成,因此我在环顾网络之后更新了我的答案.

这里有一个如何得到一个例子只有编号的和唯一的名字:

@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);
}
Run Code Online (Sandbox Code Playgroud)

希望这个更新证明是有帮助的


旧答案:

只检索特定属性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
}
Run Code Online (Sandbox Code Playgroud)

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

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


Pra*_*ore 11

interface IdOnly{
    String getId();
}

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

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


Abh*_*ngh 7

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

例子:

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

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。此解决方案更简单,特别推荐用于关联实体。注意:虽然我们已经导入了实体,但无需在查询注释中指定其包路径。 (2认同)

Cès*_*sar 5

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

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

否则,首先使用要加载的属性创建一个 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

select new org.example.RuleProjection(rule.id, rule.name) from RuleVO rule order by rule.name
Run Code Online (Sandbox Code Playgroud)

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

  • 使用新方法创建新接口。前任:

    public interface RuleRepositoryCustom {
       public List<RuleProjection> findAllWithProjection();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 更改您的存储库以扩展新界面。前任:

    public interface RuleRepository extends JpaRepository<RuleVO, Long>, RuleRepositoryCustom {
    ...
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用 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));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)