当前位置:首页 > 技术 > 正文内容

JPA原生SQL查询结果映射到实体对象实战

访客 技术 2026年5月31日 1

本文详细介绍在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语句中的字段别名必须与实体类的属性名完全一致,否则无法正确映射。同时,查询返回的字段顺序应当与实体类属性声明顺序保持一致,以确保数据准确映射到对应属性。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。