Spring Data JPA系列QueryByExampleExecutor使用详解

Spring Data JPA系列QueryByExampleExecutor使用详解

简介

Spring Data JPA 是 Spring Data 的一个模块,它通过 JPA 技术为程序开发人员提供了方便、快捷的持久化支持。Query By Example(QBE)是 Spring Data JPA 模块中的一部分,允许您根据已知的实体对象创建查询样例,可以通过 QBE 生成基于实体属性的动态查询语句。

QueryByExampleExecutor

QueryByExampleExecutor 接口提供了按实例的查询语法。该接口包含两个方法:

<S extends T> Optional<S> findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);

其中,findOne() 方法将返回与示例符合的第一个实体。如果没有找到任何实体,则返回 Optional 的空实例。

findAll() 方法将根据示例返回一个 Iterable 集合。如果没有找到任何实体,则返回空的 Iterable 实例。

ExampleMatcher

ExampleMatcher 是 Query By Example 的核心部分,它描述了对特定类型的示例应如何进行匹配。 ExampleMatcher 可以在 Query 接口级别或在基础 CRUD Repository 接口级别对应用程序执行的查询进行全局配置。

ExampleMatcher.Builder 是用于实例化 ExampleMatcher 的静态构建器。

以下代码片段说明了如何构建 ExampleMatcher 对象:

ExampleMatcher matcher = ExampleMatcher.matching()
        .withIgnorePaths("field1", "field2")
        .withMatcher("field3", matcher -> matcher.startsWith())
        .withMatcher("field4", matcher -> matcher.endsWith())
        .withMatcher("field5", matcher -> matcher.contains())
        .withMatcher("field6", matcher -> matcher.matches());

上述 ExampleMatcher 会执行以下操作:

  • 忽略名为 field1 和 field2 的属性。
  • 特定字段应以其字段值开头筛选。
  • 特定字段应以其字段值结尾。
  • 特定字段应包含其字段值。
  • 特定字段应具有与其字段值完全匹配的值。

示例1 方法级别

考虑以下 Entity:

@Entity
@Table(name = "employee")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id", nullable = false)
    private Department department;

    // ... 省略其他字段和方法
}

现在我们想按名称模糊搜索 Employee,请使用 QBE 实现此目的。

Employee employee = new Employee();
employee.setName("mark");
ExampleMatcher matcher = ExampleMatcher.matching()
        .withMatcher("name", match -> match.contains());
Example<Employee> example = Example.of(employee, matcher);
List<Employee> employees = employeeRepository.findAll(example);

上面的示例将返回符合 name 属性包含“mark”子字符串的 Employee 实例的所有结果。请注意,我们使用的是 Example 类的 of() 工厂方法来创建 Example 实例。

示例2 Query 接口级别

考虑以下 Employee Entity:

@Entity
@Table(name = "employee")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id", nullable = false)
    private Department department;

    // ... 省略其他字段和方法
}

现在我们想按部门名称以及部门经理姓名搜索 Employee,请使用 QBE 实现此目的。

首先,我们需要创建一个自定义的查询接口,这将包含我们要使用的自定义查询方法。

public interface EmployeeRepositoryCustom {

    List<Employee> findByDepartmentAndManager(String departmentName, String managerName);
}

其次,我们需要创建一个实现,它将包含我们要使用的自定义查询方法的查询方法。

@Repository
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Employee> findByDepartmentAndManager(String departmentName, String managerName) {
        Department department = new Department();
        department.setName(departmentName);
        Employee manager = new Employee();
        manager.setName(managerName);
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withIgnorePaths("id")
                .withMatcher("name", match -> match.contains());
        Example<Employee> example = Example.of(manager, matcher);
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
        Root<Employee> root = query.from(Employee.class);
        Join<Employee, Department> join = root.join("department");
        query.select(root)
                .where(criteriaBuilder.equal(join.get("name"), department.getName()),
                        criteriaBuilder.equal(root.get("manager"), manager));
        return entityManager.createQuery(query).getResultList();
    }
}

这将对名为“departmentName”的部门以及名为“managerName”的经理进行搜索。这里我们将经理实例自己创建 Example,以便可以将 Example 用于其名称。我们同时使用 QueryDSL Lambda 表达式和 JPA CriteriaBuilder 构建搜索条件和搜索结果。

最后,我们需要创建 CRUD Repository 接口和实体的 Repository 实现类。

@Transactional(readOnly = true)
public interface EmployeeRepository extends JpaRepository<Employee, Long>, QueryByExampleExecutor<Employee>, EmployeeRepositoryCustom {
}
@Repository
@Transactional(readOnly = true)
public class EmployeeRepositoryImpl extends SimpleJpaRepository<Employee, Long> implements EmployeeRepository {

    public EmployeeRepositoryImpl(EntityManager em) {
        super(Employee.class, em);
    }
}

现在,我们可以在我们的应用程序中调用我们的函数,并且将返回当前按照特定条件过滤的搜索结果集。

List<Employee> employees = employeeRepository.findByDepartmentAndManager("IT", "Mark");

总结

这篇文档介绍了 Spring Data JPA Query By Example Executor 和 ExampleMatcher 接口的细节。QueryByExampleExecutor 提供了按实例的查询语法,并允许您根据已知的实体对象创建查询样例。 ExampleMatcher 用于对如何对示例进行匹配进行描述。最后,我们提供了两个示例,演示如何使用 QBE 筛选出需要的实例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Data JPA系列QueryByExampleExecutor使用详解 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 详解如何在SpringBoot项目中使用全局异常处理

    下面我将介绍如何在Spring Boot项目中使用全局异常处理。 什么是全局异常处理 Spring Boot提供了全局异常处理机制,可以自定义异常处理,将异常统一处理。当系统中出现异常时,通过该全局异常处理机制,可以统一的返回异常信息,避免因为异常没有处理而导致系统崩溃等问题。 如何自定义全局异常处理 先创建一个自定义异常类,让其继承RuntimeExcep…

    Java 2023年5月27日
    00
  • 如何理解Java内存模型?

    如何理解Java内存模型? Java内存模型(Java Memory Model,JMM)规定了Java程序中多线程执行时,线程之间内存的交互以及对共享数据的访问方式,它是Java程序能否正确运行的重要保障。 Java内存模型的重要概念 主内存和工作内存 Java内存模型中,有两种内存: 主内存(Main Memory):所有线程可以访问共享的内存区域,主内…

    Java 2023年5月11日
    00
  • Java正则判断日期格式是否正确的方法示例

    下面是关于Java正则判断日期格式是否正确的方法示例的完整攻略。 步骤一: 导入相关类库 在使用正则表达式的时候,我们需要使用Java自带的正则表达式类来完成相关操作。因此,我们需要先在代码中导入相关类库。具体代码如下: import java.util.regex.Matcher; import java.util.regex.Pattern; 步骤二: …

    Java 2023年5月20日
    00
  • java中排序报:Comparison method violates its general contract异常的解决

    首先,我们需要了解一下“Comparison method violates its general contract”异常的意义。这个异常意味着我们在使用Java排序方法时,按照给定的比较器进行比较时违反了排序的基本规则,可能会导致排序结果出现异常,或者在使用Collections.sort()等排序方法时,发生无限递归的错误。 因此,当我们遇到这种异常时…

    Java 2023年5月27日
    00
  • Spring Boot系列教程之日志配置

    SpringBoot系列教程之日志配置 在SpringBoot项目中,对日志进行定制和配置是非常重要的。通过合理的日志配置,可以对程序进行细致的排查和问题定位。本文将针对SpringBoot项目中的日志配置进行详细的讲解。 1. 了解logback和log4j的区别 在SpringBoot默认的日志框架中,使用的是logback。但是在实际项目中,也有部分使…

    Java 2023年5月15日
    00
  • 强引用的作用是什么?

    强引用是指对象之间的一种引用关系,如果一个对象被另一个对象强引用了,那么这个对象在内存中就不能被垃圾回收器回收。在实际开发中,使用强引用的场景非常多,下面对强引用的作用进行详细讲解。 强引用的作用 1. 避免对象被回收 强引用最常见的用途就是保持对象不被垃圾回收器回收。如果一个对象被多个地方引用着,那么可以使用强引用来确保这个对象一直存在于内存中。比如,在A…

    Java 2023年5月10日
    00
  • Springboot热部署实现原理及实例详解

    Spring Boot 热部署实现原理及实例详解 什么是热部署 热部署(Hot swapping)是指在应用程序运行时,无需停止或重启应用程序,就可以实时更新部分或全部代码和配置。热部署可以提高应用程序的开发和测试效率,缩短开发和测试的周期,特别是对于大型项目和复杂项目来说,效果尤为明显。 Spring Boot 热部署实现原理 Spring Boot 应用…

    Java 2023年5月19日
    00
  • dubbo自定义异常的完整步骤与测试

    下面我会详细讲解“dubbo自定义异常的完整步骤与测试”的完整攻略: 规划异常类包结构 首先应该规划好异常类的包结构。通常情况下,我们会把异常类放在com.xxx.exception包中,这个包可以在provider、consumer、api中共用。在com.xxx.exception包中,我们可以建立一些子包,如com.xxx.exception.comm…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部