如何使用 Spring JPA 仅获取实体的选定属性?
Posted
技术标签:
【中文标题】如何使用 Spring JPA 仅获取实体的选定属性?【英文标题】:How to fetch only selected attributes of an entity using 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 的 id 和 name 属性。我怎样才能做到这一点?我发现一个通知应该可以使用 Criteria API 和 Projections 但如何?提前谢谢了。沃杰科技
【问题讨论】:
我做不到,你能做的就是延迟加载集合。我想说选择性地拉回数据没有性能优势。 参见 19.1.7 docs.jboss.org/hibernate/orm/3.3/reference/en/html/…,它基本上表明,根据上面的评论,对于非收集字段,它是可行的,但你在浪费时间。 Spring Data Projection 是此类问题的最佳解决方案。 docs.spring.io/spring-data/jpa/docs/current/reference/html/… 【参考方案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));
【讨论】:
JPQL
和 new 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/… 我刚刚检查过了。看起来查询选择了所有字段,所以这不是一个真正的解决方案。以上是关于如何使用 Spring JPA 仅获取实体的选定属性?的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot:仅访问 JPA 中的关联列值而不获取完整的关联实体
Spring Data JPA Repository:如何有条件地获取子实体
如何使用本机 SQL 在 Hibernate 中获取仅包含选定列的表实体列表?