需求:
在项目开发过程中,使用spring-data-jpa,默认repository接口查询结果要使用相应的标记了@Entity的实体接收,但是在有的情景下多表关联查询,查询出的字段可能属于不同的表,这时候就不能使用任何一个实体接收了,试了直接自定义一个没有标记@Entity的实体进行接收,sql执行时候会报错,这主要是因为,标记了@Entity的实体jpa会进行管理,和数据库相关,查询结果会用该实体进行封装;但是没有注解的实体,jpa查询结果是无法封装进去的。
PS:以上只是针对查询使用nativeQuery=true的情况下,即自定义的查询语句使用原生sql;
解决方案:
通过查询资料,发现了一个解决方案。
大致思路就是:查询时候使用jpql语句,然后查询结果使用自定义的DTO对象进行接收,需要注意的就是根据接收的字段数及顺序需要在DTO中有相应的构造方法,并且属性的名称要和@Entity实体中字段的名称一致。
自定义的DTO:
public class DTOIntelligentAnalysis {
//业务类型
private String manifestType;
//品名
private String goodsDesc;
//目的港
private String portOfDischarge;
//目的港中文名称
private String portOfDischargeValue;
//本期件数
private Long noOfPkg;
//件数单位
private String pkgUom;
//本期重量
private Long grossWeight;
//重量单位
private String grossWeightUom;
//必须要有的无参构造
public DTOIntelligentAnalysis() {}
//不同构造方法针对你查询时候查询出几个字段,需要保证字段顺序和构造方法中的一致
public DTOIntelligentAnalysis(Long noOfPkg, Long grossWeight) {
this.noOfPkg = noOfPkg;
this.grossWeight = grossWeight;
}
public DTOIntelligentAnalysis(String manifestType, String goodsDesc, String portOfDischarge,
String portOfDischargeValue, Long noOfPkg, String pkgUom, Long grossWeight, String grossWeightUom) {
this.manifestType = manifestType;
this.goodsDesc = goodsDesc;
this.portOfDischarge = portOfDischarge;
this.portOfDischargeValue = portOfDischargeValue;
this.noOfPkg = noOfPkg;
this.pkgUom = pkgUom;
this.grossWeight = grossWeight;
this.grossWeightUom = grossWeightUom;
}
……
省略get,set方法
……
}
查询语句:
@Query(value="select new cst.manifest.entity.DTOIntelligentAnalysis(sum(b.noOfPkg),sum(b.grossWeight)) from BLGoods b where b.manifestType = ?1 and b.declareTime between ?2 and ?3 and b.goodsDesc = ?4 and b.portOfDischarge=?5 group by manifestType,goodsDesc,portOfDischarge,portOfDischargeValue,pkgUom,grossWeightUom")
public DTOIntelligentAnalysis findDifferentAnalysis(String type,Date start,Date end,String goodsDesc,String portOfDischarge);
可以看出new cst.manifest.entity.DTOIntelligentAnalysis(sum(b.noOfPkg),sum(b.grossWeight)) 其实对应的构造方法中的:
public DTOIntelligentAnalysis(Long noOfPkg, Long grossWeight) {
this.noOfPkg = noOfPkg;
this.grossWeight = grossWeight;
}
这里需要注意的是jpql语句中需要使用类的全限定名,也就是包路径也要加上;猜测是spring-data-jpa在解析这个jpql语句时,会根据全限定名去查询到相应的类,然后根据相同的属性名称进行封装。
有一点疑问是:查询出的数据类型字段,要求使用Long类型,使用Integer会报错,这里不知道原因。数据库是sqlserver,grossWeight 和noOfPkg 数据库中都为int。
网友评论