Spring Data Jpa

2021-07-14 04:07

阅读:645

标签:删除   tar   帮助   oal   repos   多模板   项目   today   turn   

Introduction

在基本的数据查询实例中,可以通过实现CrudRepository接口来实现针对一个的查询或多个字段的组合查询,但这只是对于条件比较简单的情况下,如果条件比较复杂,那么一个方法的名字就会显的很长,那么就可以换一种方式来实现数据查询,比如下面即将提到的Criteria API, Specification, Query dsl.

Criteria API

CriteriaQuery

一个典型的查询代码如下:

LocalDate today = new LocalDate();

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery(Customer.class);
Root root = query.from(Customer.class);

Predicate hasBirthday = builder.equal(root.get(Customer_.birthday), today);
Predicate isLongTermCustomer = builder.lessThan(root.get(Customer_.createdAt), today.minusYears(2); 
query.where(builder.and(hasBirthday, isLongTermCustomer));
em.createQuery(query.select(root)).getResultList();

主要步骤如下:

  1. 创建查询构造器CriteriaBuilder
  2. 实例化一个条件查询
  3. 创建一个查询的根元素
  4. 创建一个或多个查询的条件预测
  5. entityManager上执行查询
CriteriaUpdate/CriteriaDelete

CriteriaQuery是jpa 2.0引入的接口,而在jpa 2.1中还引入了CriteriaUpdateCriteriaDelete接口来实现对数据的修改和删除操作。
CriteriaUpdate的实现和CriteriaQuery类似,其实现如下:

CriteriaBuilder builder = entityManager
    .getCriteriaBuilder();

CriteriaUpdate update = builder
    .createCriteriaUpdate(postModerateClass);

Root root = update.from(postModerateClass);

Expression filterPredicate = builder
.like(
    builder.lower(root.get("message")), 
    "%spam%"
);

if(Post.class.isAssignableFrom(postModerateClass)) {
    filterPredicate = builder.or(
        filterPredicate, builder
        .like(
            builder.lower(root.get("title")), 
            "%spam%"
        )
    );
}

update
.set(root.get("status"), PostStatus.SPAM)
.set(root.get("updatedOn"), new Date())
.where(filterPredicate);

return entityManager
.createQuery(update)
.executeUpdate()

当然如果觉的写那么多模板代码比较麻烦,也可以直接通过EntityManagercreateQuery接口手写sql, 也是可以的。也有其他的方法,如下面的Specification接口。

Specification接口

Specification接口实现了可重用的预测(Predicate), 一个Specification接口就是一个查询条件,可以通过创建多个Specification接口实现复杂的条件查询,其接口如下:

public interface Specification {
  Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb);
}

Root, CriteriaQuery, CriteriaBuilderCriteria中的一样,下面是一个示例:

public CustomerSpecifications {

  public static Specification customerHasBirthday() {
    return new Specification {
      public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
        return cb.equal(root.get(Customer_.birthday), today);
      }
    };
  }

  public static Specification isLongTermCustomer() {
    return new Specification {
      public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
        return cb.lessThan(root.get(Customer_.createdAt), new LocalDate.minusYears(2));
      }
    };
  }
}

为了让repository可以执行这个查询,需要repository接口实现JpaSpecificationExecutor接口。查询实例如下:

customerRepository.findAll(hasBirthday());

或者实现组合查询(jpa中提供了where, and, or 等帮助方法来简化操作):

customerRepository.findAll(where(customerHasBirthday()).and(isLongTermCustomer()));

Querydsl

开源项目Querydsl也提供了简化模板代码的实现, 你需要pom.xml中添加querydsl的包,然后添加插件以实现在每个源码包下自动创建查询类比如QCustomer

com.mysema.maven
  maven-apt-plugin
  1.0generate-sourcesprocesstarget/generated-sourcescom.mysema.query.apt.jpa.JPAAnnotationProcessor

查询代码如下:

BooleanExpression customerHasBirthday = customer.birthday.eq(today);
BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));
customerRepository.findAll(customerHasBirthday.and(isLongTermCustomer));

其中BooleanExpression和Specification类似,当然,repository需要实现相应的接口

public interface CustomerRepository extends JpaRepository, QueryDslPredicateExecutor {
}

https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
https://vladmihalcea.com/jpa-criteria-api-bulk-update-delete/

Spring Data Jpa

标签:删除   tar   帮助   oal   repos   多模板   项目   today   turn   

原文地址:https://www.cnblogs.com/helloz/p/9539340.html


评论


亲,登录后才可以留言!