使用Jpa自定义查询时,需要将查询结果自动封装对象中,有两种比较简单的方法:
方法一:返回对象为interface,只需要定义属性的get方法,jdk动态代理封装数据,执行原生sql比较方便,只需要字段和属性名一致。
数据表实体类
@Setter
@Getter
@Entity
@ToString
@DynamicUpdate
@DynamicInsert
@Table(name = "user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;// 用户ID
private String userName;// 用户名
/**** 其他字段省略 ****/
}
jpa执行原生sql查询,字段别名需要定义成对象属性名一样
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "select user_name as userName, user_id as userId from user where user_id = ?1", nativeQuery = true)
UserInt queryUserIntByUserId(Long userId);
}
另外执行原生sql查询可以自动封entity类,但是想多返回其它字段,无法封装到对象中,示例
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "select u.* from user u where u.user_id = ?1", nativeQuery = true)
User queryByUserId(Long userId);
}
自定义结果,UserInt只能定义为interface,结果将由jdk动态代理封装结果,不足之处是将结果打印日志,不会显示内容,因为没有toString方法,显示内容org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap@6c09dcc2
public interface UserInt{
/** 用户名 */
String getUserName();
/** 用户ID */
Long getUserId();
}
方法二:返回对象为自定义class,可定义toString方法,打印日志方便。对象属性不要求名称一致。
jpa执行HQL查询,在查询时对结果进行封装,注意这里使用的构造方法一定要写自定义类的全包名,不写全包名会报错
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "select new com.xxx.vo.UserVo(u.userId, u.userName) from User u where u.userId = ?1")
UserVo queryUserVoByUserId(Long userId);
}
自定义结果,UserVo定义为class,需要定义封装数据的构造方法
package com.xxx.vo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
@NoArgsConstructor
public class UserVo {
private Long userId;// 用户ID
private String userName;// 用户名
public UserVo(Long userId, String userName) {
super();
this.userId = userId;
this.userName= userName;
}
}
总结:
方法一适合执行原生SQL查询,字段名称和接口get方法一致即可,不足之处,将结果对象打印日志不显示内容,转json之后是{},可以调用接口方法一个一个打印;
方法二适合执行HQL查询,不可执行原生SQL,字段名不需要一致,只需要构造方法参数位置正确;