温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring Data JPA在@Query中怎么使用投影

发布时间:2022-07-18 13:52:19 来源:亿速云 阅读:176 作者:iii 栏目:开发技术

本篇内容主要讲解“Spring Data JPA在@Query中怎么使用投影”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring Data JPA在@Query中怎么使用投影”吧!

Spring Data JPA 在 @Query 中使用投影的方法

测试代码

@Test
public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned() {
        PersonView personView = personRepository.findByLastName("Doe");
}
public interface PersonView {
    String getLastName();
}
@Entity
public class Person {
    @Id
    private Long id;
    private String firstName;
    private String lastName;
}

执行的 SQL

select person0_.last_name as col_0_0_ from person person0_ where person0_.last_name=?

然后当我换成自定义查询的方式时,效果就变成了这样:

测试代码

@Query("select p from Person p where p.lastName = ?1")
PersonView findByLastNameByQuery(String lastName);
@Test
public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned2() {
        PersonView personView = personRepository.findByLastNameByQuery("Doe");
}

执行的SQL

select person0_.id as id1_6_, person0_.first_name as first_na2_6_, person0_.last_name as last_nam3_6_ from person person0_ where person0_.last_name=?

可以看到这里是查询了全部的字段(实在是让人摸不着头脑)。

后来有同事提醒说是因为我写了select p导致的,我就尝试写明要查询的字段(但还是无法理解为什么在这种情况下投影直接不生效):
测试代码

@Query("select p.lastName from Person p where p.lastName = ?1")
PersonView findByLastNameByQuery(String lastName);

执行的 SQL

select person0_.last_name as col_0_0_ from person person0_ where person0_.last_name=?

从 SQL 上来看,这样写已经是实现了我想要的效果,可是实际上真正使用这个代码的时候,坑就又来了:
测试代码

@Test
public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned2() {
        PersonView personView = personRepository.findByLastNameByQuery("Doe");
        assertThat(personView.getLastName()).isEqualTo("Doe");
}

加了一行断言来模拟使用的场景
执行结果

org.opentest4j.AssertionFailedError: 
expected: "Doe"
 but was: null
Expected :"Doe"
Actual   :null

直接黑人问号脸。

分析了一下,执行的 SQL 没有问题,投影类也没有问题,那问题就是出在结果集映射的时候了。虽然没看过 JPA 的代码,但是最终肯定是基于 JDBC API 的,而JDBC API是怎么处理结果集映射的?
翻一翻 ResultSet 类可以看到一共有两种方法获取结果:by indexby name,仔细看看执行的 SQL,person0_.last_name as col_0_0_ last_name 自动生成了一个别名叫col_0_0_,而投影类中能获得的信息只有字段名last_name而没有别名col_0_0_,所以 by name 的路走不通;
那么by index呢,很明显也不行,我这里的示例只有一个字段,假如有两个字段,那么SQL 中的字段的顺序和投影类中的字段的顺序就无法保证一致,从而就无法根据 index 来获取想要的对应的结果。

然后就是验证环节了,假如是因为名字映射不上导致的结果为 null,那我就给你一个能对应的名字:
测试代码

@Query("select p.lastName as lastName from Person p where p.lastName = ?1")
PersonView findByLastNameByQuery(String lastName);

@Test
public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned2() {
        PersonView personView = personRepository.findByLastNameByQuery("Doe");
        assertThat(personView.getLastName()).isEqualTo("Doe");
}

执行的 SQL

select person0_.last_name as col_0_0_ from person person0_ where person0_.last_name=?

虽然执行的 SQL 上还是用了自动生成的别名,但是断言却通过了,猜测是 JPA 在解析 Query 的时候存储了手动声明的别名信息。

到此,相信大家对“Spring Data JPA在@Query中怎么使用投影”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI