JPA多表原生查询仅返回单表数据,如何获取全量数据用于Jasper报表
问题根因
你当前Repository方法的返回类型为List<Dispense>,JPA原生查询仅会将查询结果映射到返回类型对应实体的字段,因此即便SQL拉取了4个表的全量数据,最终也只会保留Dispense表对应的字段值。
解决方案
方案1:使用接口投影(实现最简单,无需额外复杂配置)
首先定义一个投影接口,包含你需要的四个表所有字段的getter方法,示例如下:
public interface InvoiceProjection { // patient表对应字段的getter Long getPatientId(); String getPatientName(); // 其余需要的patient字段自行补充 // consult表对应字段的getter Long getConsultId(); java.util.Date getConsultTime(); // 其余需要的consult字段自行补充 // script表对应字段的getter Long getScriptId(); String getScriptContent(); // 其余需要的script字段自行补充 // dispense表对应字段的getter Long getDispenseId(); String getIcd10(); String getTariffCode(); String getDispenseItem(); java.math.BigDecimal getPrice(); }
修改Repository方法的返回类型为该投影接口:
@Query( value = "SELECT p.*, c.*, s.*, d.* from patient p, consult c ,script s,dispense d " + " where p.patient_id=c.patient_id " + " and c.consult_id = d.consult_id " + " and c.fk_script_id =s.script_id" + " and c.consult_id=?1 ", nativeQuery = true ) List<InvoiceProjection> findInvoiceByConsultId(Long consultId);
最后修改Controller的返回类型即可:
@RequestMapping(value = "/api/invoice/{consultId}",method = {RequestMethod.GET}) public List<InvoiceProjection> invoice(@PathVariable(value="consultId")Long consultId){ return dispenseRepository.findInvoiceByConsultId(consultId); }
方案2:使用@SqlResultSetMapping自定义POJO映射(更适合Jasper报表开发,结构稳定兼容性好)
首先定义包含所有需要字段的DTO类,添加全参构造函数:
public class InvoiceDTO { // 依次定义patient、consult、script、dispense需要的字段 private Long patientId; private String patientName; private Long consultId; private Long scriptId; private Long dispenseId; private String icd10; private String tariffCode; private String dispenseItem; private java.math.BigDecimal price; // 其余需要的字段自行补充 // 全参构造函数,参数顺序要和SQL查询返回的字段顺序完全一致 public InvoiceDTO(Long patientId, String patientName, Long consultId, Long scriptId, Long dispenseId, String icd10, String tariffCode, String dispenseItem, java.math.BigDecimal price) { this.patientId = patientId; this.patientName = patientName; this.consultId = consultId; this.scriptId = scriptId; this.dispenseId = dispenseId; this.icd10 = icd10; this.tariffCode = tariffCode; this.dispenseItem = dispenseItem; this.price = price; } // 补充所有字段的getter方法 }
在任意一个JPA实体类上添加结果集映射配置(可以直接加在现有Dispense实体类上):
@SqlResultSetMapping( name = "InvoiceMapping", classes = @ConstructorResult( targetClass = InvoiceDTO.class, columns = { // 这里的column顺序、类型要和SQL查询返回的字段顺序、类型完全匹配,name为SQL返回的数据库字段名 @ColumnResult(name = "patient_id", type = Long.class), @ColumnResult(name = "patient_name", type = String.class), @ColumnResult(name = "consult_id", type = Long.class), @ColumnResult(name = "script_id", type = Long.class), @ColumnResult(name = "dispense_id", type = Long.class), @ColumnResult(name = "icd10", type = String.class), @ColumnResult(name = "tariff_code", type = String.class), @ColumnResult(name = "dispense_item", type = String.class), @ColumnResult(name = "price", type = java.math.BigDecimal.class) // 其余需要的字段按顺序补充 } ) ) @Entity public class Dispense { // 原有Dispense实体的代码保持不变 }
修改Repository方法,指定结果集映射:
@Query( value = "SELECT p.*, c.*, s.*, d.* from patient p, consult c ,script s,dispense d " + " where p.patient_id=c.patient_id " + " and c.consult_id = d.consult_id " + " and c.fk_script_id =s.script_id" + " and c.consult_id=?1 ", nativeQuery = true, resultSetMapping = "InvoiceMapping" ) List<InvoiceDTO> findInvoiceByConsultId(Long consultId);
最后修改Controller返回类型为List<InvoiceDTO>即可。
方案3:返回List<Object[]>(仅适合临时调试,不推荐正式使用)
直接修改Repository返回类型为List<Object[]>,查询返回的每个Object数组按SQL字段顺序存储四个表的字段值,可自行遍历封装成需要的结构,但可读性和维护性差,不适合正式业务场景。
内容的提问来源于stack exchange,提问作者hoosain.madhi
相关产品推荐
相关产品推荐

