Spring Data Jpa 复杂查询方式总结(多表关联及自定义分页)

网友投稿 606 2022-08-26


Spring Data Jpa 复杂查询方式总结(多表关联及自定义分页)

目录SpringDataJpa复杂查询总结1.查找出Id小于3,并且名称带有shanghai的记录2.通过旅店名称分页查询旅店以及城市的所有信息3.HQL通过旅店名称查询旅店以及城市的所有信息4.HQL通过旅店名称查询旅店以及城市的所有信息直接返回实体类5.动态查询旅店以及城市的所有信息直接返回实体类JPA#复杂查询#自定义查询编写自定义SQL基于下面信息基于最前面的信息,要编写自定义SQL

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会自动的在数据库中生成表结构.

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

新建接口

public interface TCityRepository extends JpaRepository, JpaSpecificationExecutor {

}

单元测试seGhvpf类

@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(seGhvpfvalue = "select t1.name as cityName,t2.name as hotelName\n" +

"from t_city t1\n" +

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

"where t2.name = :name",

countQuery = "select count(*)" +

"from t_city t1 \n" +

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

"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

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语句去调用

JPA#复杂查询#自定义查询

编写自定义SQL基于下面信息

1. SpringData JPA 在为Repository接口生成实现的时候http://,会查找是否有 "接口名称"+"Impl"的类,如果有的话,就把这个类的方法合并到要生成的实现当中。

假设:要为接口StudentRepository编写自定义sql查询。

基于最前面的信息,要编写自定义SQL

需要下面三步:

1. 自定义一个接口,在在接口中声明方法StudentCoustomRepository,这个自定义接口名称不重要;

2. 让目标接口继承自定义接口,这样目标接口就有了相应的方法;

3. 编写自定义方法的实现类,这个类需要使用"目标接口名称"+"Impl"为类名,

即StudentRepositoryImpl,这样SpringDataJpa 为StudentRepository生成实现的时候就会包含这里面的方法了。

public class StudentRepositoryImpl implements StudentCoustomRepository {

// 这里可以写很复杂的SQL,作为演示之用,就不弄那么复杂

private static final String SQL = "select * from t_student where name like :name ";

@PersistenceContext

private EntityManager em;

@SuppressWarnings({ "rawtypes", "unchecked" })

@Override

public List findByName(String name) {

Query query = em.createNativeQuery(SQL).setParameter("name", "%"+name+"%");

query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

List queryList = query.getResultList();

if (queryList.size() == 0) {

System.out.println("找不到Student name为" + name + "的记录");

return null;

}

List retVal = new ArrayList<>();

for(Object o : queryList) {

Map student = (Map)o;

StudentVO vo = new StudentVO();

try {

// org.apache.commons.beanutils.BeanUtils;

// 使用apaches的beanutil,直接吧map转为实例

BeanUtils.populate(vo, student);

retVal.add(vo);

} catch (IllegalAccessException | InvocationTargetException e) {

System.out.println("解析StudentVO bean时发生异常:" + e.getMessage());

}

}

return retVal;

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Scrapy 框架【学习笔记01】(scrapy官网)
下一篇:Request/Response【学习笔记03】(requests response)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~