JPA原生SQL查询结果映射到实体对象实战
本文详细介绍在JPA中使用原生SQL语句进行查询,并将返回结果自动转换为实体对象的方法。本示例基于Oracle数据库环境,涵盖精确匹配、模糊搜索以及分页查询三种常见场景。
核心实现方式
将原生SQL查询结果映射到实体对象需要使用EntityManager的createNativeQuery方法,并指定目标实体类的Class对象。
实体类定义
实体类必须使用@Entity注解标注为JPA实体,同时需要使用@Id注解标识主键字段,否则在执行查询时会抛出异常。
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Course {
@Id
private Long courseId;
private Long studentId;
private String description;
// 省略getter和setter方法
@Override
public String toString() {
return "Course [courseId=" + courseId + ", studentId=" + studentId + ", description=" + description + "]";
}
}
场景一:精确条件查询
使用WHERE子句进行精确匹配查询,参数通过命名参数方式绑定。
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
public class CourseQueryService {
@PersistenceContext
private EntityManager entityManager;
public List<Course> findByCourseId(Long courseId) {
String sql = "SELECT t.course_id AS courseId, t.student_id AS studentId, t.description AS description "
+ "FROM t_course t WHERE t.course_id = :courseId";
Query query = entityManager.createNativeQuery(sql, Course.class);
query.setParameter("courseId", courseId);
List<Course> courses = query.getResultList();
System.out.println("查询结果:" + courses);
return courses;
}
}
场景二:模糊查询
在Oracle数据库中,字符串连接使用双竖线(||)操作符,模糊查询需要使用LIKE关键字并拼接通配符。
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
public class CourseQueryService {
@PersistenceContext
private EntityManager entityManager;
public List<Course> searchByDescription(String keyword) {
String sql = "SELECT t.course_id AS courseId, t.student_id AS studentId, t.description AS description "
+ "FROM t_course t WHERE t.description LIKE '%' || :keyword || '%'";
Query query = entityManager.createNativeQuery(sql, Course.class);
query.setParameter("keyword", keyword);
List<Course> courses = query.getResultList();
System.out.println("模糊查询结果:" + courses);
return courses;
}
}
场景三:Oracle分页查询
Oracle的分页实现需要借助rownum伪列,通过子查询嵌套实现。具体逻辑是:先对结果集添加行号,然后筛选指定范围的记录。
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
public class CourseQueryService {
@PersistenceContext
private EntityManager entityManager;
public List<Course> findByPage(Integer pageNumber, Integer pageSize, String keyword) {
// 基础查询语句
String baseSql = "SELECT t.course_id AS courseId, t.student_id AS studentId, t.description AS description "
+ "FROM t_course t WHERE t.description LIKE '%' || :keyword || '%' ORDER BY t.course_id";
// Oracle分页实现:嵌套子查询
String paginatedSql = "SELECT * FROM (SELECT a.*, ROWNUM AS row_num FROM ("
+ baseSql + ") a WHERE ROWNUM <= " + (pageNumber + 1) * pageSize
+ ") b WHERE b.row_num > " + pageNumber * pageSize;
Query query = entityManager.createNativeQuery(paginatedSql, Course.class);
query.setParameter("keyword", keyword);
List<Course> courses = query.getResultList();
System.out.println("分页查询结果:" + courses);
return courses;
}
}
常见异常及解决方案
在使用JPA原生SQL查询过程中,可能会遇到以下几种错误:
1、ORA-01747错误
执行时报错"ORA-01747: invalid user.table.column, table.column, or column specification",通常是SQL语句中的字段名与Oracle数据库保留关键字冲突导致。建议检查WHERE条件中的字段命名是否使用了SQL关键字,必要时对字段名加引号或使用别名。
2、Unknown entity异常
报错"javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown entity",表示实体类未被正确注册。需要在实体类上添加@Entity注解,确保该类位于EntityManager扫描的包路径下。
3、No identifier异常
报错"org.hibernate.AnnotationException: No identifier specified for entity",原因是没有为主键字段添加@Id注解。JPA要求每个实体必须至少有一个使用@Id注解标注的主键字段。
使用注意事项
在使用createNativeQuery方法进行结果映射时,SQL语句中的字段别名必须与实体类的属性名完全一致,否则无法正确映射。同时,查询返回的字段顺序应当与实体类属性声明顺序保持一致,以确保数据准确映射到对应属性。