参考:
Spring Data JPA - Reference Documentation
The best way to use the JPA SqlResultSetMapping - Vlad Mihalcea
JPA @MappedSuperclass 注解 | 範宗雲
开发过程中,虽然JPA提供了常见的CRUD方法,并以接口的方式暴露给我们使用者,会让我们不用再编写基础的增删改查方法,但是JPA在自定义映射结果集上,并不能直接去拿一个pojo
去承接查询的结果,比如下面这样
@Query(value = "xxxx")
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配置文件用的比较少,这里记录一下使用注解的方式进行配置
基于注解的配置方式可以减少一个配置的引入
@Entity
@NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {
}
如上所示,此命名查询的名称即为:User.findByEmailAddress
如果在别处需要使用到此命名查询,那么可以使用JPA的EntityManager
调用
@PersistenceContext
private EntityManager entityManager;
entityManager.createNamedQuery("User.findByEmailAddress").getResultList();
或者,在其实体类对应的Repository
接口中,声明此方法
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastname(String lastname);
User findByEmailAddress(String emailAddress);
}
自定义映射结果集
有时我们通过命名查询得到的结果集,需要转换为另外一种类型的Java类。
这个时候就需要我们使用到自定义映射
。
首先在我们的实体类上写好自定义查询,并使用
@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(
name= "getAllLogs",
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",
resultClass = OperateLog.class,
resultSetMapping = "logMapping"
) }) @SqlResultSetMapping( name = “logMapping”, classes = @ConstructorResult(
targetClass = OperateLog.class,
columns = {
@ColumnResult(name = "ID", type = Integer.class),
@ColumnResult(name = "OPERATE_INFO", type = String.class),
@ColumnResult(name = "OPERATE_TIME", type = LocalDateTime.class),
@ColumnResult(name = "BE_OPERATED_ID", type = Integer.class),
@ColumnResult(name = "OPERATOR_ID", type = Integer.class)
}
) ) // 下面实体类省略了部分信息 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; }
2. 在DTO上声明`@MappedSuperclass`
> **@MappedSuperclass**:表明这个类只是某一个实体类的子集,并不是一个完整的实体类,并不会在数据库中生成对应的数据表
```java
/**
* Created By Intellij IDEA
*
* @author Xinrui Yu
* @version 1.0
* @date 2022/6/10 16:35 星期五
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
public class OperateLog {
private Integer id;
private String operateInfo;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime operateTime;
private Integer beOperatedId;
private Integer operatorId;
}
- 使用
entityManager
调用方法即可