Spring Boot执行Inner Join查询报错,需实现Angular前端数据展示
解决Spring Boot HQL关联查询报错及关联数据获取问题
问题概述
执行INNER JOIN查询时抛出错误:
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: persona is not mapped
对应的HQL语句为:
SELECT name,apellidos,fechaturno,medico FROM persona c INNER JOIN turnos c1 ON c.id = c1.idturno
需求是获取用户(Persona)的姓名、姓氏,以及其关联的预约(Turno)日期和医生信息,最终在Angular前端展示。
错误原因分析
- HQL语法错误:HQL是面向实体类的查询,需使用实体类名称(首字母大写),而非数据库表名。原HQL中使用了小写的
persona、turnos,Hibernate无法匹配到对应的映射实体。 - 关联条件错误:
Turno与Persona的关联依赖实体中的persona字段(@ManyToOne注解),无需手动写数据库字段的关联条件。 - 返回类型不匹配:查询返回的是零散字段组合,但方法声明返回
List<Turno>,类型完全不兼容。
修复步骤
1. 创建DTO封装查询结果
因为查询返回的是跨实体的零散字段,需要自定义DTO类来接收数据:
public class PersonaTurnoDTO { private String name; private String apellidos; private String fechaturno; private String medico; // 构造方法需与查询字段顺序完全一致 public PersonaTurnoDTO(String name, String apellidos, String fechaturno, String medico) { this.name = name; this.apellidos = apellidos; this.fechaturno = fechaturno; this.medico = medico; } // Getter方法 public String getName() { return name; } public String getApellidos() { return apellidos; } public String getFechaturno() { return fechaturno; } public String getMedico() { return medico; } }
2. 修正Repository中的HQL查询
使用实体类名和已有的实体关联关系重构查询,指定返回DTO类型:
@Repository public interface TurnoRepository extends JpaRepository<Turno, Integer> { // 查询所有用户的预约信息 @Query("SELECT new com.yourpackage.dto.PersonaTurnoDTO(p.name, p.apellidos, t.fechaturno, t.medico) FROM Persona p INNER JOIN p.turnos t") List<PersonaTurnoDTO> findAllPersonaTurnos(); // 根据用户ID查询其专属预约信息 @Query("SELECT new com.yourpackage.dto.PersonaTurnoDTO(p.name, p.apellidos, t.fechaturno, t.medico) FROM Persona p INNER JOIN p.turnos t WHERE p.id = :personaId") List<PersonaTurnoDTO> findPersonaTurnosByPersonaId(@Param("personaId") int personaId); // 保留原有方法 Turno findById(int idturno); }
注意替换com.yourpackage.dto为你实际的DTO包路径。
3. 新增Service层封装逻辑(可选)
如果需要在Service层处理业务逻辑,新增对应方法:
@Service public class TurnoService { @Autowired private TurnoRepository turnoRepository; public List<PersonaTurnoDTO> getAllPersonaTurnos() { return turnoRepository.findAllPersonaTurnos(); } public List<PersonaTurnoDTO> getPersonaTurnosByPersonaId(int personaId) { return turnoRepository.findPersonaTurnosByPersonaId(personaId); } }
4. 编写REST接口供Angular调用
创建Controller提供数据接口:
@RestController @RequestMapping("/api/turnos") public class TurnoController { @Autowired private TurnoService turnoService; @GetMapping("/persona-turnos") public ResponseEntity<List<PersonaTurnoDTO>> getAllPersonaTurnos() { List<PersonaTurnoDTO> data = turnoService.getAllPersonaTurnos(); return ResponseEntity.ok(data); } @GetMapping("/persona-turnos/{personaId}") public ResponseEntity<List<PersonaTurnoDTO>> getPersonaTurnosByPersonaId(@PathVariable int personaId) { List<PersonaTurnoDTO> data = turnoService.getPersonaTurnosByPersonaId(personaId); return ResponseEntity.ok(data); } }
Angular前端展示实现
定义数据接口
export interface PersonaTurno { name: string; apellidos: string; fechaturno: string; medico: string; }
组件中获取并展示数据
import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { PersonaTurno } from './models/persona-turno.model'; @Component({ selector: 'app-persona-turnos', templateUrl: './persona-turnos.component.html' }) export class PersonaTurnosComponent implements OnInit { personaTurnos: PersonaTurno[] = []; constructor(private http: HttpClient) {} ngOnInit(): void { this.http.get<PersonaTurno[]>('/api/turnos/persona-turnos') .subscribe(data => { this.personaTurnos = data; }); } }
HTML模板渲染数据
<table> <thead> <tr> <th>姓名</th> <th>姓氏</th> <th>预约日期</th> <th>医生</th> </tr> </thead> <tbody> <tr *ngFor="let item of personaTurnos"> <td>{{ item.name }}</td> <td>{{ item.apellidos }}</td> <td>{{ item.fechaturno }}</td> <td>{{ item.medico }}</td> </tr> </tbody> </table>
内容的提问来源于stack exchange,提问作者Federico Andres Ratcliffe
相关产品推荐
相关产品推荐

