如何使用 Spring JPA 仅获取实体的选定属性?
How to fetch only selected attributes of an entity using Spring 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
您可以使用@Query 注释(HQL) 来完成。
请参阅下面的 Spring 文档:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
(在 spring 文档中搜索 @Query)
更新:
正如有人向我指出的那样,我很懒惰,这可以很好地完成,因此我在网上寻找合适的答案后更新了我的答案。
下面是如何获取仅 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 数据库,因为您总是 select行是一个实体。
你可以做的是查询实体中的变量,例如:
@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 节
是的,你可以用投影来实现。您有多种应用方式:
如果您可以升级到 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 class 名称,另一种选择是使用 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));
}
}
您还可以定义自定义构造函数以使用 JPQL 获取特定列。
示例:
Replace {javaPackagePath} with complete java package path of the class
use as a constructor in 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);
}
interface IdOnly{
String getId();
}
@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
public List<IdOnly> findAllByName(String name);
}
我注意到这是一个非常古老的 post,但如果有人仍在寻找答案,请试试这个。它对我有用。
我在我的项目中使用 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
您可以使用@Query 注释(HQL) 来完成。
请参阅下面的 Spring 文档:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
(在 spring 文档中搜索 @Query)
更新:
正如有人向我指出的那样,我很懒惰,这可以很好地完成,因此我在网上寻找合适的答案后更新了我的答案。
下面是如何获取仅 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 数据库,因为您总是 select行是一个实体。
你可以做的是查询实体中的变量,例如:
@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 节
是的,你可以用投影来实现。您有多种应用方式:
如果您可以升级到 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 class 名称,另一种选择是使用 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)); } }
您还可以定义自定义构造函数以使用 JPQL 获取特定列。
示例:
Replace {javaPackagePath} with complete java package path of the class use as a constructor in 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);
}
interface IdOnly{
String getId();
}
@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
public List<IdOnly> findAllByName(String name);
}
我注意到这是一个非常古老的 post,但如果有人仍在寻找答案,请试试这个。它对我有用。