jpa使用jpql 原生sql 方法命名规则 实现多表联查和分页
jpql查询
jpql多表联查方式有两种
-
使用VO(view object)做映射与投影; 即建立一个vo类,该类中包含了要查询的字段,然后在jpql中使用new 类名(属性1,属性2.......) from 的方式查询
注意:一定要使用new 的方式 且最好使用类名的完全限定名 ,字段的位置必须一致
-
使用接口方式接收 属性分命名为 getXXX ,****如 getMenuId() 方式 ;
推荐使用VO方式查询
案例: 查询角色拥有的菜单
VO方式查询
- 新建一个vo实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysMenuRoleDTO {
private Long menuId;
private String menuName;
private Long roleId;
private String roleName;
}
- 写查询接口
@Query("select new com.lonni.dtos.SysMenuRoleDTO(menu.menuId,menu.menuName,ro.roleId,ro.roleName) from SysMenu menu join SysRoleMenu ru on menu.menuId=ru.menuId " +
"join SysRole ro on ro. roleId=ru.roleId")
Page<SysMenuRoleDTO> getMenuRoleDto(Pageable pageable);
注意这里: new com.lonni.dtos.SysMenuRoleDTO(menu.menuId,menu.menuName,ro.roleId,ro.roleName)
这里一定要是new 的方式 且最好使用完全限定名,否则会找不到
- 调用接口
@Test
public void testJpqlJoinVo(){
Page<SysMenuRoleDTO> menuRoleDto = dao.getMenuRoleDto(PageRequest.of(0, 1));
System.out.println(menuRoleDto);
System.out.println(menuRoleDto.getTotalElements());
System.out.println(menuRoleDto.getContent());
System.out.println(menuRoleDto.getTotalPages());
}
使用接口方式
- 新建一个接口
注意格式,一定要是getXXX
的方式
/**
* 使用接口方式接收返回值
*/
public interface SysMenuRole {
Long getMenuId();
String getMenuName();
Long getRoleId();
String getRoleName();
}
- 写dao层接口
//使用jpql多表查询 使用接口查询方式
//案列 :角色拥有的菜单
@Query("select menu.menuId,menu.menuName,ro.roleId,ro.roleName from SysMenu menu join SysRoleMenu ru on menu.menuId=ru.menuId " +
"join SysRole ro on ro. roleId=ru.roleId")
Page<SysMenuRole> getMenuRoleDtoByInterface(Pageable pageable);
这里直接就可以使用字段属性方式绑定了
- 调用
//测试jpql 多表查询 使用接口方式
@Test
public void testJpqlJoinInterface(){
Page<SysMenuRole> menuRoleDto = dao.getMenuRoleDtoByInterface(PageRequest.of(0, 1));
System.out.println(menuRoleDto);
System.out.println(menuRoleDto.getTotalElements());
System.out.println(menuRoleDto.getContent());
System.out.println(menuRoleDto.getTotalPages());
List<SysMenuRole> content = menuRoleDto.getContent();
for (SysMenuRole sysMenuRole : content) {
System.out.println(sysMenuRole.getMenuId());
System.out.println(sysMenuRole.getMenuName());
}
}
在获取的时候比较麻烦,需要遍历list 然后一个一个的拿到数据
原生sql查询
基本语法
原生sql查询和jpql一样,只是需要设置query注解的*nativeQuery=true*
语法:
@Query(value = "select * from sys_menu menu ",nativeQuery=true)
注意:使用原生sql查询就是查询表了 ,而不是查询实体 所以from后面的一定是数据库表名,且属性一定是数据库字段
分页
- 分页的返回值不能是javaBean,因为使用原生sql查询了,就不会有字段映射了,最好使用
Page<Map>
- 分页直接加上 Pageable 参数
- 原生sql****分页时不能使用别名 ,否则报错 (折腾了很久o.o)
接口定义 :
//测试原生sql是否支持分页
//jpql 分页查询
@Query(value = " select * from sys_menu ",nativeQuery = true)
Page<Map> getSysPage(Pageable pageable);
调用 :
//测试原生sql是否支持分页
@Test
public void testSqlPage(){
Page<Map> sysPage = dao.getSysPage(PageRequest.of(0, 2));
System.out.println(sysPage.getTotalPages());
System.out.println(sysPage.getContent());
}
方法命名规则查询
只需要按照jpa提供的方法名称规则定义方法,不需要自定义jpql
约定:
- findBy :标识查询操作
对象中的属性(首字母大写):查询条件,如:findByMenuId 标识根据菜单id查询数据- 模糊查询
findByMenuNameLike( "测试%");
传值必须使用sql模糊匹配语法,否则还是全匹配查询 - 多条件查询
findByMenuIdOrMenuName
;使用and or
等
- 模糊查询
注意:使用方法命名规则查询参数的顺序必须和findBy后的一致
- 使用方法定义查询 全匹配查询
List<SysMenu> findByMenuIdOrMenuName(long menuId, String menuName);
- 使用方法定义查询 模糊查询
List<SysMenu> findByMenuNameLike(String menuName);