Spring Data JPA QueryByExampleExecutor

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Spring Data JPA QueryByExampleExecutor

AKone   2022-09-29 我要评论

1、QueryByExampleExecutor用法

在前面章节中,我们介绍了DMQ 和 @Query两种查询方法,除此之外,还有QueryByExampleExecutor查询方法。

1.1 介绍

QueryByExampleExecutor是一种用户友好的查询技术,具有简单的接口,它允许动态创建,并且不需要填写包含字段名称的查询。

1.2 QueryByExampleExecutor接口

public interface QueryByExampleExecutor<T> {
   // 根据实体查询条件、查找一个对象
   <S extends T> Optional<S> findOne(Example<S> example);
   // 根据实体查询条件、查询一批对象
   <S extends T> Iterable<S> findAll(Example<S> example);
   // 根据实体查询条件并排序、查询一批对象
   <S extends T> Iterable<S> findAll(Example<S> example, Sort sort);
   // 根据实体查询条件并分页,查询一批对象
   <S extends T> Page<S> findAll(Example<S> example, Pageable pageable);
   // 根据实体查询条件、查询符合条件的对象个数
   <S extends T> long count(Example<S> example);
   // 根据实体查询条件、判断是否有符合条件的对象
   <S extends T> boolean exists(Example<S> example);
   // 根据实体查询条件、判断是否有符合条件的对象
   <S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
}

1.3 QueryByExampleExecutor实践

第一步 :创建User实体和UserAddress实体

// User表
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = "address")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    @OneToMany(mappedBy = "user",fetch = FetchType.LAZY)
    private List<UserAddress> address;
}
// Address表
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "user")
public class UserAddress {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String address;
    @ManyToOne(cascade = CascadeType.ALL)
    private User user;
}

第二步: 编写DAO层,JpaRepository已经继承QueryByExampleExceutor

public interface UserAddressRepo extends JpaRepository<UserAddress,Integer>  {
}

第三步:测试

@Test
public void test01 () {
    User user = User.builder()
            .name("jack")
            .email("123456@126.com")
            .age(20)
            .build();
    userAddressRepo.saveAll(Lists.newArrayList(UserAddress.builder()
            .address("shanghai").user(user).build(),UserAddress.builder()
            .address("beijing").user(user).build()));
}
@Test
public void testQBEE() throws JsonProcessingException {
    User user = User.builder()
            .name("jack")
            .age(20)
            .email("12345")
            .build();
    UserAddress userAddress = UserAddress.builder()
            .address("shanghai")
            .user(user)
            .build();
    ObjectMapper objectMapper = new ObjectMapper();
    // 创建匹配器,构建动态查询条件
    ExampleMatcher exampleMatcher = ExampleMatcher.matching()
            .withMatcher("user.email",ExampleMatcher.GenericPropertyMatchers.startsWith())
            .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.startsWith());
    Page<UserAddress> u = userAddressRepo.findAll(Example.of(userAddress,exampleMatcher), PageRequest.of(0,2));
    System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(u));
}

一开始写这个代码的时候,我也比较懵逼, Example是什么?ExampleMatcher是什么? 下面我一一介绍。

1.4 Example语法详解

首先:我们先看Example的源码

public interface Example<T> {
   static <T> Example<T> of(T probe) {
      return new TypedExample<>(probe, ExampleMatcher.matching());
   }
   static <T> Example<T> of(T probe, ExampleMatcher matcher) {
      return new TypedExample<>(probe, matcher);
   }
   T getProbe();
   ExampleMatcher getMatcher();
   @SuppressWarnings("unchecked")
   default Class<T> getProbeType() {
      return (Class<T>) ProxyUtils.getUserClass(getProbe().getClass());
   }
}
  • probe:实际实体类,即查询条件的封装类(又可以理解为查询条件参数)
  • ExampleMatcher :匹配器,匹配特定字段的匹配规则。
  • Example:由probe 和 ExampleMatcher租车,由于创建查询,即组合查询参数和参数的匹配规则。

创建Example的两个方法 :

  • static Example of(T probe):需要一个实体参数,即查询条件。而里面的ExampleMatcher采用默认的ExamoleMatcher.matching(); 表示忽略NULL,所有字段采用精准匹配
  • static Example of(T probe, ExampleMatcher matcher):需要两个参数构建Example,也就表示ExampleMatcher自由组合规则,正如我们上面的测试用例里面的代码一样。

1.5 ExampleMatcher语法分析

上图是ExampleMatcher向外暴露的方法,我们只要关心返回值为ExampleMatcher类型的方法。

其中有三个方法我们需要注意一下:

static ExampleMatcher matching() {
   return matchingAll();
}
static ExampleMatcher matchingAll() {
   return new TypedExampleMatcher().withMode(MatchMode.ALL);
}

上述的这两种方法表达的意思是一样的。两者采用的都是MatcheMode.ALL的模式,即AND模式,生成的SQL如下:

Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where (useraddres0_.address like ? escape ?) and user1_.name=? and (user1_.email like ? escape ?) and user1_.age=20

可以看到,这些查询条件都是AND的关系。再看另外一种方法

static ExampleMatcher matchingAny() {
   return new TypedExampleMatcher().withMode(MatchMode.ANY);
}

当前方法与上面两个方法不一样的地方在于:第三个MatchMode.Any,表示查询条件是or的关系

Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.age=20

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们