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<TCity, Integer>, JpaSpecificationExecutor<TCity> { 
}

单元测试类

@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<TCity> findByIdLessThanAndNameLike(int id, String name);

单元测试

@Test
public void findByIdLessThanAndNameLike() throws Exception {
    List<TCity> shanghai = tCityRepository.findByIdLessThanAndNameLike(3, "%shanghai%");
    Assert.assertTrue(shanghai.size() > 0);
}

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

/**
 * 通过旅店名称分页查询旅店以及城市的信息
 *
 * @param name     旅店名称
 * @param pageable 分页信息
 * @return Page<Object[]>
 */
@Query(value = "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<Object[]> findCityAndHotel(@Param("name") String name, Pageable pageable);

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

单元测试

 @Test
public void findCityAndHotel() throws Exception {
    Page<Object[]> cityAndHotel = tCityRepository.findCityAndHotel("酒店", new PageRequest(0, 10));
    Assert.assertTrue(cityAndHotel.getTotalElements() > 0);
}    

关于把List<Object[]> 转换成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<Map<String, Object>> findCityAndHotelByHQL(@Param("name") String name);

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

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

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<CityHohel> 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<CityHohel> 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<CityHohel> findCityAndHotelAllSelf(@Param("name") String name, Pageable pageable);
@Test
public void findCityAndHotelAllSelf() throws Exception {
    Page<CityHohel> 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接口生成实现的时候,会查找是否有 "接口名称"+"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<StudentVO> 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<StudentVO> 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;
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring data jpa的使用与详解(复杂动态查询及分页,排序)

    一. 使用Specification实现复杂查询 (1) 什么是Specification Specification是springDateJpa中的一个接口,他是用于当jpa的一些基本CRUD操作的扩展,可以把他理解成一个spring jpa的复杂查询接口.其次我们需要了解Criteria 查询,这是是一种类型安全和更面向对象的查询.而Spring Data JPA支持JPA2.0的Criteria查询,相应的接口是JpaSpecificationExecutor. 而JpaSpecifica

  • Spring Data JPA 复杂/多条件组合分页查询

    话不多说,请看代码: public Map<String, Object> getWeeklyBySearch(final Map<String, String> serArgs, String pageNum, String pageSize) throws Exception { // TODO Auto-generated method stub Map<String,Object> resultMap=new HashMap<String, Object&

  • Spring Data JPA 实现多表关联查询的示例代码

    多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果,这里介绍第二种方式. 一.一对一映射 实体 UserInfo :用户. 实体 Address:家庭住址. 这里通过外键的方式(一个实体通过外键关联到另一个实体的主键)来实现一对一关联. 实体类 1.实体类 UserInfo.java package com.johnfnash.learn.domain; import java.io.Ser

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

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

  • Spring Data JPA 简单查询--方法定义规则(详解)

    一.常用规则速查 1 And 并且 2 Or   或 3 Is,Equals 等于 4 Between   两者之间 5 LessThan 小于 6 LessThanEqual   小于等于 7 GreaterThan 大于 8 GreaterThanEqual   大于等于 9 After 之后(时间) > 10 Before 之前(时间) < 11 IsNull 等于Null 12 IsNotNull,NotNull 不等于Null 13 Like 模糊查询.查询件中需要自己加 % 14

  • 详解Spring Data Jpa 模糊查询的正确用法

    模糊查询 Spring Data Jpa的使用可以减少开发者对sql语句的编写,甚至完全不需要编写sql语句.但是,开发过程中总会遇到各种复杂的场景以及大大小小的坑. 今天项目中某个功能模块需要用到模糊查询.原生sql中模糊查询关键字'Like',而Spring Data Jpa的Repository接口中恰恰也有实体字段对应的Like.但是,如果直接使用它,那么恭喜你,你幸运地掉坑了. Spring Data Jpa 模糊查询正确用法 首先,我们先创建一个实体用来存储我们的数据 /** * 实

  • 关于spring data jpa 模糊查询like的坑点

    目录 spring data jpa 模糊查询like坑点 spring data jpa like 查询问题 spring data jpa 模糊查询like坑点 在 ServiceImpl 中 调用, 不要忘记 % factoryinfoDao.findByFactorynameLike("%"+input+"%") spring data jpa like 查询问题 在使用Spring Data Jpa Like时 在继承JpaRepository的一个接口中

  • 解决Spring Data Jpa 实体类自动创建数据库表失败问题

    目录 Spring Data Jpa 实体类自动创建数据库表失败 找了半天发现是一个配置的问题 可能导致JPA 无法自动建表的问题汇总 1.没加@Entity或引错Entity所在包 2.jpa配置中ddl-auto未设置update 3.实体类的包不是启动程序所在包的子包 4.mysql配置问题 5.依赖不全 6.实体类间关系错误 7.启动类注解问题 8.其他问题 Spring Data Jpa 实体类自动创建数据库表失败 先说一下我遇到的这个问题,首先我是通过maven创建了一个spring

  • Spring Data JPA实现查询结果返回map或自定义的实体类

    目录 Spring Data JPA查询结果返回map或自定义的实体类 1.工具类 2.具体应用 spingboot:jpa:Spring data jpa 返回map 结果集 Spring Data JPA查询结果返回map或自定义的实体类 在JPA中我们可以使用entityManager.createNativeQuery()来执行原生的SQL语句,并且JPA的底层实现都是支持返回Map对象的. 例如: EclipseLink 的 query.setHint(QueryHints.RESUL

  • Spring Data JPA实现查询结果返回map或自定义的实体类

    目录 SpringDataJPA查询结果返回map或自定义的实体类 1.工具类 2.具体应用 spingboot:jpa:Springdatajpa返回map结果集 Spring Data JPA查询结果返回map或自定义的实体类 在JPA中我们可以使用entityManager.createNativeQuery()来执行原生的SQL语句,并且JPA的底层实现都是支持返回Map对象的. 例如: EclipseLink 的 query.setHint(QueryHints.RESULT_TYPE

  • Spring Data Jpa 中原生查询 REGEXP 的使用详解

    目录 Spring Data Jpa原生查询 REGEXP 的使用 spring data jpa 原生查询(查一个json中的某一字段) Spring Data Jpa原生查询 REGEXP 的使用 REGEXP 与like 有通用之处, 单 regexp 有更好的精确度,更加自由灵活 在jpa 中使用时 :其中 定位符 ^ 在jpa @query 注解中使用时需要加上引用号 e.g @Query(value = "select p.id as id from zt_products AS p

  • 使用Spring Data JPA的坑点记录总结

    前言 Spring-data-jpa的基本介绍:JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现.在ORM框架中,Hibernate是一支很大的部队,使用很广泛,也很方便,能力也很强,同时Hibernate也是和JPA整合的比较良好,我们可以认为JPA是标准,事实上也是,JPA几乎都是接口,实现都是Hibernate在做,宏观上面看,在JPA的统一之下Hibernate很良好的运行. 最近在

  • Spring Data JPA中 in 条件参数的传递方式

    关于Spring Data JPA中自定义sql 条件的 in参数记录 此文做一个记录,以便以后观看,也希望正在遇到同样问题的同学能有所启发,如果你有更好的方法,或我的做法有问题,请告知下,非常感谢. 下面写两种简单做法,注意下地方: 在此我只记录HQL 中 in 后面参数问题,细节查询方法相关代码就略过,还请见谅 查询接口: /** ** paramString : 自定义 hql ** paramMap : hql中查询条件的参数 ** start:数据开始条数 ** max:最大数据条数

随机推荐