Spring Data Jpa复杂查询的示例分析
小编给大家分享一下SpringDataJpa复杂查询的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
Spring Data Jpa复杂查询总结只是做一个总结所以就不多说废话了
实体类
@Entity@Table(name="t_hotel")@DatapublicclassTHotel{@Idprivateintid;privateStringname;privateStringaddress;/***城市id*/privateStringcity;}
@Entity@Table(name="t_city")@DatapublicclassTCity{@Idprivateintid;privateStringname;privateStringstate;privateStringcountry;privateStringmap;}
在启动SpringBoot的时候 SpringDataJpa会自动的在数据库中生成表结构.
为了查询要求,我随便的增加了一些数据,如下图所示
新建接口
publicinterfaceTCityRepositoryextendsJpaRepository<TCity,Integer>,JpaSpecificationExecutor<TCity>{}
单元测试类
@RunWith(SpringRunner.class)@SpringBootTestpublicclassTCityRepositoryTest{@AutowiredprivateTCityRepositorytCityRepository;}1.查找出Id小于3,并且名称带有shanghai的记录
/***查找出Id小于3,并且名称带有`shanghai`的记录.**@paramidid*@paramname城市名称*@return城市列表*/List<TCity>findByIdLessThanAndNameLike(intid,Stringname);
单元测试
@TestpublicvoidfindByIdLessThanAndNameLike()throwsException{List<TCity>shanghai=tCityRepository.findByIdLessThanAndNameLike(3,"%shanghai%");Assert.assertTrue(shanghai.size()>0);}2.通过旅店名称分页查询旅店以及城市的所有信息
/***通过旅店名称分页查询旅店以及城市的信息**@paramname旅店名称*@parampageable分页信息*@returnPage<Object[]>*/@Query(value="selectt1.nameascityName,t2.nameashotelName\n"+"fromt_cityt1\n"+"leftjoint_hotelt2ont2.city=t1.id\n"+"wheret2.name=:name",countQuery="selectcount(*)"+"fromt_cityt1\n"+"leftjoint_hotelt2ont2.city=t1.id\n"+"wheret2.name=:name",nativeQuery=true)Page<Object[]>findCityAndHotel(@Param("name")Stringname,Pageablepageable);
为了节约时间 我只在select 与 from 之间 分别查询了城市的名称以及旅店的名称如果要查所有的信息,可以换成t1.* ,t2.*
单元测试
@TestpublicvoidfindCityAndHotel()throwsException{Page<Object[]>cityAndHotel=tCityRepository.findCityAndHotel("酒店",newPageRequest(0,10));Assert.assertTrue(cityAndHotel.getTotalElements()>0);}
关于把List<Object[]> 转换成List<对象> 的方法 我已经在上一篇JPA的文章中比较清楚的说了,因此我就不再重复的叙述一遍了
3.HQL通过旅店名称查询旅店以及城市的所有信息3和2其实是一样的,为了方便我就不作出分页查询了
HQL可以用map来接受返回的参数,具体的用法如下所示:
/***HQL通过旅店名称查询旅店以及城市的所有信息**@return*/@Query(value="selectnewmap(t1,t2)fromTCityt1leftjoinTHotelt2ont1.id=t2.citywheret2.name=:name")List<Map<String,Object>>findCityAndHotelByHQL(@Param("name")Stringname);
测试方法和2是差不多的 我就不粘贴了
Map<String.Object> 转换实体类的方法也挺多的我就不多说了,如果是直接返回给前台的话,也没有必要转换成对象.
4.HQL通过旅店名称查询旅店以及城市的所有信息 直接返回实体类/***关联查询**@return*/@Query(value="selectnewpers.zpw.domain.CityHohel(t1.nameAScityName,t2.nameAShotelName)fromTCityt1leftjoinTHotelt2ont1.id=t2.citywheret2.name=:name")List<CityHohel>findCityAndHotelByHQLResultObj(@Param("name")Stringname);
为了方便CityHohel我只封装了2个属性,这和HQL查询的字段是完全一致的,也必须要保持一致.
/***CreatedbyZhuPengWeion2018/5/12.*/@DatapublicclassCityHohel{privateStringcityName;privateStringhotelName;publicCityHohel(StringcityName,StringhotelName){this.cityName=cityName;this.hotelName=hotelName;}}
当然这个带参的构造方法是必须要写的,否则会抛出转换实体的异常
单元测试
@TestpublicvoidfindCityAndHotelByHQLResultObj()throwsException{List<CityHohel>cityAndHotelByHQLResultObj=tCityRepository.findCityAndHotelByHQLResultObj("酒店");Assert.assertTrue(cityAndHotelByHQLResultObj.size()>0);}
4.HQL通过旅店名称分页查询旅店以及城市的所有信息 直接返回实体类
/***关联查询**@return*/@Query(value="selectnewpers.zpw.domain.CityHohel(t1.nameAScityName,t2.nameAShotelName)fromTCityt1leftjoinTHotelt2ont1.id=t2.citywheret2.name=:name",countQuery="selectcount(*)fromTCityt1leftjoinTHotelt2ont1.id=t2.citywheret2.name=:name")Page<CityHohel>findCityAndHotelAllSelf(@Param("name")Stringname,Pageablepageable);
@TestpublicvoidfindCityAndHotelAllSelf()throwsException{Page<CityHohel>cityAndHotelAllSelf=tCityRepository.findCityAndHotelAllSelf("酒店",newPageRequest(0,10));Assert.assertTrue(cityAndHotelAllSelf.getTotalElements()>0);}5.动态查询旅店以及城市的所有信息 直接返回实体类
如果是动态查询的话当然首先得构造一条sql去查询了,当然如果不是自定义实体对象的话这样的网上一大堆我就不写了.
直接走测试
@Autowired@PersistenceContextprivateEntityManagerentityManager;@TestpublicvoidtestDynamic()throwsException{Stringsql="selectnewpers.zpw.domain.CityHohel(t1.nameAScityName,t2.nameAShotelName)fromTCityt1leftjoinTHotelt2ont1.id=t2.citywheret2.name='酒店'";Queryquery=entityManager.createQuery(sql);ListresultList=query.getResultList();Assert.assertTrue(resultList.size()>0);}
这样测试是通过的,因此可以知道在业务层的方法中我们可以动态的构造SQL语句. 比如说可以在接口中这样子来定义一个方法
/***自定义查询*@paramsql*@paramentityManager*@return*/defaultListcustomQuery(Stringsql,EntityManagerentityManager){returnentityManager.createQuery(sql).getResultList();}
然后在测试类中动态的根据条件去拼接SQL语句去调用
JPA#复杂查询#自定义查询编写自定义SQL基于下面信息1. SpringData JPA 在为Repository接口生成实现的时候,会查找是否有 "接口名称"+"Impl"的类,如果有的话,就把这个类的方法合并到要生成的实现当中。
假设:要为接口StudentRepository编写自定义sql查询。
基于最前面的信息,要编写自定义SQL需要下面三步:
1. 自定义一个接口,在在接口中声明方法StudentCoustomRepository,这个自定义接口名称不重要;
2. 让目标接口继承自定义接口,这样目标接口就有了相应的方法;
3. 编写自定义方法的实现类,这个类需要使用"目标接口名称"+"Impl"为类名,
即StudentRepositoryImpl,这样SpringDataJpa 为StudentRepository生成实现的时候就会包含这里面的方法了。
publicclassStudentRepositoryImplimplementsStudentCoustomRepository{//这里可以写很复杂的SQL,作为演示之用,就不弄那么复杂privatestaticfinalStringSQL="select*fromt_studentwherenamelike:name";@PersistenceContextprivateEntityManagerem;@SuppressWarnings({"rawtypes","unchecked"})@OverridepublicList<StudentVO>findByName(Stringname){Queryquery=em.createNativeQuery(SQL).setParameter("name","%"+name+"%");query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);ListqueryList=query.getResultList();if(queryList.size()==0){System.out.println("找不到Studentname为"+name+"的记录");returnnull;}List<StudentVO>retVal=newArrayList<>();for(Objecto:queryList){Mapstudent=(Map)o;StudentVOvo=newStudentVO();try{//org.apache.commons.beanutils.BeanUtils;//使用apaches的beanutil,直接吧map转为实例BeanUtils.populate(vo,student);retVal.add(vo);}catch(IllegalAccessException|InvocationTargetExceptione){System.out.println("解析StudentVObean时发生异常:"+e.getMessage());}}returnretVal;}}
以上是“SpringDataJpa复杂查询的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。