为什么80%的码农都做不了架构师?>>>
有时候不想放弃jpa持久化的便利性,又不想因此牺牲了查询的灵活性,所以列举两种jpa下的灵活查询方式。
-
单表查询指定Entity中的部分字段
这块比较简单,只需要定义一个存放部分属性的类,包含全部参数的构造函数的必须有的
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrginfoDTO {
String orgcode;
String orgname;
}
然后在repository中定义接口
@Query("select new com.xxx.domain.OrginfoDTO(t1.orgcode, t1.orgname) from Orginfo t1")
Page findAllDTO(Pageable pageable);
测试这个方法,日志中会打出sql,只会查询指定的那几个字段,而jpa默认的不是select *
Hibernate: select t1.orgcode, t1.orgname from Orginfo t1 limit 10 offset 0
-
联表查询多个Entity中的关联字段
由于现在的项目基本不会用到外键,所以也没有在jpa中设置@ManyToOne,@ManyToMany等关联注解,
所有的Entity中的属性都基本类型,没有任何关联关系,这的确防止jpa自动在表中生成外键,
但是由此带来的字段翻译呈现是个痛点,如何用spring data jpa实现联表查询呢,
下面的DTO中包含了两张表中的字段,Orginfo中有areacode,Areainfo表中有地区名称
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrginfoDTO {
String orgcode;
String orgname;
String areaname;
}
然后在Orginfo这个Entity中声明你的结果DTO,并在@NamedNativeQuery中写好的你本地查询sql
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
@SqlResultSetMapping(
name = "OrginfoDTO",
classes = {
@ConstructorResult(
targetClass = OrginfoDTO.class,
columns = {
@ColumnResult(name = "orgcode", type = String.class),
@ColumnResult(name = "orgname", type = String.class),
@ColumnResult(name = "areaname", type = String.class)
}
)
}
)
@NamedNativeQuery(
name = "Orginfo.findAllDTONative",
query = "select t1.orgcode, t1.orgname, t2.name as areaname from Orginfo t1, Areainfo t2 where t1.areacode = t2.code and t1.orgtype = :orgtype limit 10 offset 0",
resultSetMapping = "OrginfoDTO"
)
@Slf4j
@Entity
@Table(name="orginfo")
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false)
@ToString(callSuper=true)
@NoArgsConstructor
public class Orginfo {
...
}
接着写repository中的接口,接口中的方法名称必须与@NamedNativeQuery中的name对应,同时nativeQuery必须声明为true,不然它会认为你执行的不是native sql而是hql
@Query(nativeQuery=true)
List findAllDTONative(@Param("orgtype") Integer orgtype);
下面我们执行以下单元测试,看下日志是否如我们所期望的
Hibernate: select t1.orgcode, t1.orgname, t2.name as areaname from Orginfo t1, Areainfo t2 where t1.areacode = t2.code and t1.orgtype = ? limit 10 offset 0
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : native totals: 10
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310240099, orgname=21085684341, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310215099, orgname=测试账户, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310246099, orgname=绍兴市雪花机电有限公司1, areaname=绍兴市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310236091, orgname=北京中全清茂展览展示有限公司IWW, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310231091, orgname=电子同城联调六, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310230091, orgname=test, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310224091, orgname=杭州光大测试2, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310223099, orgname=测试专用对公1, areaname=杭州市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310248091, orgname=孙悟空, areaname=宁波市)
2017-12-05 15:01:56.286 INFO 12540 --- [ main] c.e.o.domain.OrginfoRepositoryTest : OrginfoDTO(orgcode=3310216099, orgname=业务测试有限公司53069, areaname=杭州市)
的确联表只查询了所需要的三个字段,并且组装到dto中成功输出。