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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37167422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:05:17  来源:igfitidea点击:

How to fetch only selected attributes of an entity using Spring JPA?

springhibernatespring-bootjpaspring-data-jpa

提问by Vojtech

I'm using Spring Boot (1.3.3.RELEASE) and Hibernate JPA in my project. My entity looks like this:

我在我的项目中使用 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;
}

My repository looks like this:

我的存储库如下所示:

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

In some cases I need to fetch only idand nameattributes of entity RuleVO. How can I achieve this? I found a notice it should be doable using Criteria API and Projections but how? Many thanks in advance. Vojtech

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

回答by Roel Strolenberg

UPDATE:

更新:

As has been pointed out to me, I'm lazy and this can very well be done hence I'm updating my answer after having looked around the web for a proper one.

正如向我指出的那样,我很懒惰,这可以很好地完成,因此我在网上寻找合适的答案后更新了我的答案。

Here's an example of how to get onlythe id's and onlythe names:

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

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

Hopefully this update proves helpful

希望此更新证明有帮助



Old Answer:

旧答案:

Only retrieving the specific attributes name/id is not possible as this is not how spring was designed or any SQL database for that matter as you always select a row which is an entity.

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

What you CAN do is query over the variables in the entity, for instance:

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

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

You can modify these however you want w.r.t. your needs. You can call these methods directly via the autowired repository

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

See http://docs.spring.io/spring-data/jpa/docs/current/reference/html/Section 5.3 for more options and examples

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

回答by Pranjal Gore

interface IdOnly{
    String getId();
}

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

I notice that this is a very old post, but if someone is still looking for an answer, try this. It worked for me.

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

回答by Abhilekh Singh

You can also define custom constructor to fetch specific columns using JPQL.

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

Example:

例子:

Replace {javaPackagePath} with complete java package path of the class use as a constructor in 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);
}

回答by Cèsar

Yes, you can achieve it with projections. You have many ways to apply them:

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

If you could upgrade to Spring Data Hopper, it provides an easy to use support for projections. See how to use them in the reference documentation.

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

Otherwise, first of all create a DTO with the attributes you want to load, something like:

否则,首先使用要加载的属性创建一个 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;
    }
}

Of course, you could use Lombok annotations also.

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

Then, you can use in the JPQL queries like this:

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

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

Another option, if you want to avoid using DTO class names in your queries, is to implement your own query method using QueryDSL. With Spring Data JPA, you have to:

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

  • Create a new interface with the new method. Ex:

    public interface RuleRepositoryCustom {
       public List<RuleProjection> findAllWithProjection();
    }
    
  • Change your repository to extend the new interface. Ex:

    public interface RuleRepository extends JpaRepository<RuleVO, Long>, RuleRepositoryCustom {
    ...
    
  • Create an implementation of the Custom repository using the Spring Data JPA QueryDSL support. You have to previously generate the Q clases of QueryDSL, using its Maven plugin. Ex:

    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));
        }
    }
    
  • 使用新方法创建新接口。前任:

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

回答by shankarsh15

You can do it by using @Query annotation(HQL).

您可以使用@Query annotation(HQL) 来实现。

Please refer to the Spring docs below:

请参考下面的 Spring 文档:

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

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

(search for @Query in spring document)

(在spring文档中搜索@Query)