• Spring Data Jpa 复杂查询总结


      实体类

      @Entity

      @Table(name = "t_hotel")

      @Data

      public class THotel {

      @Id

      private int id;

      private String name;

      private String address;

      /**

      * 城市id

      */

      private String city;

      }

      @Entity

      @Table(name = "t_city")

      @Data

      public class TCity {

      @Id

      private int id;

      private String name;

      private String state;

      private String country;

      private String map;

      }

      在启动SpringBoot的时候 SpringDataJpa会自动的在数据库中生成表结构.

      为了查询要求,我随便的增加了一些数据,如下图所示

      

    image

      新建接口

      public interface TCityRepository extends JpaRepository, JpaSpecificationExecutor {

      }

      单元测试类

      @RunWith(SpringRunner.class)

      @SpringBootTest

      public class TCityRepositoryTest{

      @Autowired

      private TCityRepository tCityRepository;

      }

      1.查找出Id小于3,并且名称带有shanghai的记录.

      /**

      * 查找出Id小于3,并且名称带有`shanghai`的记录.

      *

      * @param id id

      * @param name 城市名称

      * @return 城市列表

      */

      List findByIdLessThanAndNameLike(int id, String name);

      单元测试

      @Test

      public void findByIdLessThanAndNameLike() throws Exception {

      List shanghai = tCityRepository.findByIdLessThanAndNameLike(3, "%shanghai%");

      Assert.assertTrue(shanghai.size() > 0);

      }

      2.通过旅店名称分页查询旅店以及城市的所有信息

      /**

      * 通过旅店名称分页查询旅店以及城市的信息

      *

      * @param name 旅店名称

      * @param pageable 分页信息

      * @return Page

      */

      @Query(value = "select t1.name as cityName,t2.name as hotelName " +

      "from t_city t1 " +

      " left join t_hotel t2 on t2.city = t1.id " +

      "where t2.name = :name",

      countQuery = "select count(*)" +

      "from t_city t1 " +

      " left join t_hotel t2 on t2.city = t1.id " +

      "where t2.name = :name"

      , nativeQuery = true)

      Page findCityAndHotel(@Param("name") String name, Pageable pageable);

      为了节约时间 我只在select 与 from 之间 分别查询了城市的名称以及旅店的名称如果要查所有的信息,可以换成

      t1.* ,

      t2.*

      单元测试

      @Test

      public void findCityAndHotel() throws Exception {

      Page cityAndHotel = tCityRepository.findCityAndHotel("酒店", new PageRequest(0, 10));

      Assert.assertTrue(cityAndHotel.getTotalElements() > 0);

      }

      关于把List 转换成List<对象> 的方法 我已经在上一篇JPA的文章中比较清楚的说了,因此我就不再重复的叙述一遍了

      3.HQL通过旅店名称查询旅店以及城市的所有信息

      3和2其实是一样的,为了方便我就不作出分页查询了

      HQL可以用map来接受返回的参数,具体的用法如下所示:

      /**

      * HQL通过旅店名称查询旅店以及城市的所有信息

      *

      * @return

      */

      @Query(value = "select new map(t1,t2) from TCity t1 left join THotel t2 on t1.id=t2.city where t2.name =:name")

      List> findCityAndHotelByHQL(@Param("name") String name);

      测试方法和2是差不多的 我就不粘贴了

      Map 转换实体类的方法也挺多的我就不多说了,如果是直接返回给前台的话,也没有必要转换成对象.

      4.HQL通过旅店名称查询旅店以及城市的所有信息 直接返回实体类

      /**

      * 关联查询

      *

      * @return

      */

      @Query(value = "select new pers.zpw.domain.CityHohel(t1.name AS cityName,t2.name AS hotelName) from TCity t1 left join THotel t2 on t1.id=t2.city where t2.name =:name")

      List findCityAndHotelByHQLResultObj(@Param("name") String name);

      为了方便CityHohel我只封装了2个属性,这和HQL查询的字段是完全一致的,也必须要保持一致.

      /**

      * Created by ZhuPengWei on 2018/5/12.

      */

      @Data

      public class CityHohel {

      private String cityName;

      private String hotelName;

      public CityHohel(String cityName, String hotelName) {

      this.cityName = cityName;

      this.hotelName = hotelName;

      }

      }

      当然这个带参的构造方法是必须要写的,否则会抛出转换实体的异常

      单元测试

      @Test 无锡人流医院 http://www.wxbhnk120.com/

      public void findCityAndHotelByHQLResultObj() throws Exception {

      List cityAndHotelByHQLResultObj = tCityRepository.findCityAndHotelByHQLResultObj("酒店");

      Assert.assertTrue(cityAndHotelByHQLResultObj.size() > 0);

      }

      4.HQL通过旅店名称分页查询旅店以及城市的所有信息 直接返回实体类

      /**

      * 关联查询

      *

      * @return

      */

      @Query(value = "select new pers.zpw.domain.CityHohel(t1.name AS cityName,t2.name AS hotelName) from TCity t1 left join THotel t2 on t1.id=t2.city where t2.name =:name",

      countQuery = "select count(*) from TCity t1 left join THotel t2 on t1.id=t2.city where t2.name =:name")

      Page findCityAndHotelAllSelf(@Param("name") String name, Pageable pageable);

      @Test

      public void findCityAndHotelAllSelf() throws Exception {

      Page cityAndHotelAllSelf = tCityRepository.findCityAndHotelAllSelf("酒店", new PageRequest(0, 10));

      Assert.assertTrue(cityAndHotelAllSelf.getTotalElements() > 0);

      }

      5.动态查询旅店以及城市的所有信息 直接返回实体类

      如果是动态查询的话当然首先得构造一条sql去查询了,当然如果不是自定义实体对象的话这样的网上一大堆我就不写了.

      直接走测试

      @Autowired

      @PersistenceContext

      private EntityManager entityManager;

      @Test

      public void testDynamic() throws Exception {

      String sql = "select new pers.zpw.domain.CityHohel(t1.name AS cityName,t2.name AS hotelName) from TCity t1 left join THotel t2 on t1.id=t2.city where t2.name ='酒店'";

      Query query = entityManager.createQuery(sql);

      List resultList = query.getResultList();

      Assert.assertTrue(resultList.size() > 0);

      }

      这样测试是通过的,因此可以知道在业务层的方法中我们可以动态的构造SQL语句. 比如说可以在接口中这样子来定义一个方法

      /**

      * 自定义查询

      * @param sql

      * @param entityManager

      * @return

      */

      default List customQuery(String sql, EntityManager entityManager) {

      return entityManager.createQuery(sql).getResultList();

      }

      然后在测试类中动态的根据条件去拼接SQL语句去调用

  • 相关阅读:
    [原][诗]送幼儿园杨老师
    [原]由智能音箱被黑联想到。。。人类灭亡
    [转]VS中的路径宏 OutDir、ProjectDir、SolutionDir各种路径含义
    [原]globalmapper设置高程配色(globalmapper自定义配色方案)
    [原]JSON 字符串(值)做判断,比较 “string ”
    [转]使用 curl 发送 POST 请求的几种方式
    [转]c++多线程编程之pthread线程深入理解
    [转]c++ pthread 多线程简介
    Linux下ps -ef和ps aux的区别
    Java三种方式实现栈和队列
  • 原文地址:https://www.cnblogs.com/djw12333/p/11281975.html
Copyright © 2020-2023  润新知