参考:
Spring Data JPA - Reference Documentation
The best way to use the JPA SqlResultSetMapping - Vlad Mihalcea
JPA @MappedSuperclass 注解 | 範宗雲
开发过程中,虽然JPA提供了常见的CRUD方法,并以接口的方式暴露给我们使用者,会让我们不用再编写基础的增删改查方法,但是JPA在自定义映射结果集上,并不能直接去拿一个pojo去承接查询的结果,比如下面这样

  1. @Query(value = "xxxx")
  2. List<UserBaseDTO> getUserBaseInfo(Pageable pageable);

这样的自定义查询在JPA中是不允许的
但查询某个实体的部分属性是我们开发中不可避免会使用到的
因为我们需要使用到命名查询自定义映射结果集


命名查询

作用:给某一条语句起一个唯一的名字,可以在其他的地方使用到此查询语句。

The examples use the <named-query /> element and @NamedQuery annotation. The queries for these configuration elements have to be defined in the JPA query language. Of course, you can use <named-native-query /> or @NamedNativeQuery too. These elements let you define the query in native SQL by losing the database platform independence.

配置:可以通过XML配置文件和注解的方式进行配置,但个人XML配置文件用的比较少,这里记录一下使用注解的方式进行配置
基于注解的配置方式可以减少一个配置的引入

  1. @Entity
  2. @NamedQuery(name = "User.findByEmailAddress",
  3. query = "select u from User u where u.emailAddress = ?1")
  4. public class User {
  5. }

如上所示,此命名查询的名称即为:User.findByEmailAddress
如果在别处需要使用到此命名查询,那么可以使用JPA的EntityManager调用

  1. @PersistenceContext
  2. private EntityManager entityManager;
  3. entityManager.createNamedQuery("User.findByEmailAddress").getResultList();

或者,在其实体类对应的Repository接口中,声明此方法

  1. public interface UserRepository extends JpaRepository<User, Long> {
  2. List<User> findByLastname(String lastname);
  3. User findByEmailAddress(String emailAddress);
  4. }

然后通过注入Bean即可调用到此方法

自定义映射结果集

有时我们通过命名查询得到的结果集,需要转换为另外一种类型的Java类。
这个时候就需要我们使用到自定义映射

  1. 首先在我们的实体类上写好自定义查询,并使用@ConstructorResult注解,表明我们使用的是DTO类的构造器进行转换 ```java /**

    • Created By Intellij IDEA *
    • @author Xinrui Yu
    • @date 2022/4/11 9:54 星期一 */ @Entity @Table(name = “t_user_logs”) @Data @AllArgsConstructor @NoArgsConstructor @ApiModel(value = “用户操作日志”) @NamedNativeQueries({ @NamedNativeQuery(

      1. name= "getAllLogs",
      2. query = "SELECT d.ID, d.OPERATE_INFO, d.OPERATE_TIME, d.BE_OPERATED_ID, d.OPERATOR_ID FROM( SELECT v.*, ROWNUM RN FROM ( SELECT * FROM T_USER_LOGS UNION ALL SELECT * FROM T_DEPT_LOGS UNION ALL SELECT * FROM T_DEVICE_LOG) v ) d WHERE d.RN >= ?1 AND d.RN <= ?2 ORDER BY d.OPERATE_TIME DESC",
      3. resultClass = OperateLog.class,
      4. resultSetMapping = "logMapping"

      ) }) @SqlResultSetMapping( name = “logMapping”, classes = @ConstructorResult(

      1. targetClass = OperateLog.class,
      2. columns = {
      3. @ColumnResult(name = "ID", type = Integer.class),
      4. @ColumnResult(name = "OPERATE_INFO", type = String.class),
      5. @ColumnResult(name = "OPERATE_TIME", type = LocalDateTime.class),
      6. @ColumnResult(name = "BE_OPERATED_ID", type = Integer.class),
      7. @ColumnResult(name = "OPERATOR_ID", type = Integer.class)
      8. }

      ) ) // 下面实体类省略了部分信息 public class UserLog implements Serializable {

      private static final long serialVersionUID = 1245163531241359551L; private Integer id; private User operateUser; private User beOperatedUser; private String operateInfo; private LocalDateTime operateTime; }

  1. 2. DTO上声明`@MappedSuperclass`
  2. > **@MappedSuperclass**:表明这个类只是某一个实体类的子集,并不是一个完整的实体类,并不会在数据库中生成对应的数据表
  3. ```java
  4. /**
  5. * Created By Intellij IDEA
  6. *
  7. * @author Xinrui Yu
  8. * @version 1.0
  9. * @date 2022/6/10 16:35 星期五
  10. */
  11. @Data
  12. @AllArgsConstructor
  13. @NoArgsConstructor
  14. @MappedSuperclass
  15. public class OperateLog {
  16. private Integer id;
  17. private String operateInfo;
  18. @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  19. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
  20. private LocalDateTime operateTime;
  21. private Integer beOperatedId;
  22. private Integer operatorId;
  23. }
  1. 使用entityManager调用方法即可