新建两个实体
@Entity(name = "UserInfoEntity")
@Table(name = "user_info", schema = "test")
public class UserInfoEntity implements Serializable {@Id@Column(name = "id", nullable = false)private Integer id;@Column(name = "first_name", nullable = true, length = 100)private String firstName;@Column(name = "last_name", nullable = true, length = 100)private String lastName;@Column(name = "telephone", nullable = true, length = 100)private String telephone;@Column(name = "create_time", nullable = true)private Date createTime;@Column(name = "version", nullable = true)private String version;@OneToOne(optional = false,fetch = FetchType.EAGER)@JoinColumn(referencedColumnName = "id",name = "address_id",nullable = false)@Fetch(FetchMode.JOIN)private UserReceivingAddressEntity addressEntity;
......
}@Entity
@Table(name = "user_receiving_address", schema = "test")
public class UserReceivingAddressEntity implements Serializable {@Id@Column(name = "id", nullable = false)private Integer id;@Column(name = "user_id", nullable = false)private Integer userId;@Column(name = "address_city", nullable = true, length = 500)private String addressCity;
......
}
UserRepository 需要继承 JpaSpecificationExecutor
public interface UserRepository extends JpaSpecificationExecutor<UserInfoEntity> { }
调用者 UserInfoManager 的写法
- 我们演示一下直接用 lambda 使用 Root<T> 和 CriteriaBuilder 做一个简单的不同条件的查询和链表查询。
@Component
public class UserInfoManager {@Autowiredprivate UserRepository userRepository;public Page<UserInfoEntity> findByCondition(UserInfoRequest userParam,Pageable pageable){return userRepository.findAll((root, query, cb) -> {List<Predicate> predicates = new ArrayList<Predicate>();if (StringUtils.isNoneBlank(userParam.getFirstName())){//liked的查询条件predicates.add(cb.like(root.get("firstName"),"%"+userParam.getFirstName()+"%"));}if (StringUtils.isNoneBlank(userParam.getTelephone())){//equal查询条件predicates.add(cb.equal(root.get("telephone"),userParam.getTelephone()));}if (StringUtils.isNoneBlank(userParam.getVersion())){//greaterThan大于等于查询条件predicates.add(cb.greaterThan(root.get("version"),userParam.getVersion()));}if (userParam.getBeginCreateTime()!=null&&userParam.getEndCreateTime()!=null){//根据时间区间去查询 predicates.add(cb.between(root.get("createTime"),userParam.getBeginCreateTime(),userParam.getEndCreateTime()));}if (StringUtils.isNotBlank(userParam.getAddressCity())) {//联表查询,利用root的join方法,根据关联关系表里面的字段进行查询。predicates.add(cb.equal(root.join("addressEntityList").get("addressCity"), userParam.getAddressCity()));}return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();}, pageable);}
}
//可以仔细体会上面这个案例,实际工作中应该大部分都是这种写法,就算扩展也是百变不离其中。
- 我们再来看一个不常见的复杂查询的写法,来展示一下 CriteriaQuery 的用法(作者已经强烈不推荐了哦,和上面比起来太不优雅了)。
public List<MessageRequest> findByConditions(String name, Integer price, Integer stock) { messageRequestRepository.findAll((Specification<MessageRequest>) (itemRoot, query, criteriaBuilder) -> {//这里用 List 存放多种查询条件,实现动态查询List<Predicate> predicatesList = new ArrayList<>();//name 模糊查询,like 语句if (name != null) {predicatesList.add(criteriaBuilder.and(criteriaBuilder.like(itemRoot.get("name"), "%" + name + "%")));}// itemPrice 小于等于 <= 语句if (price != null) {predicatesList.add(criteriaBuilder.and(criteriaBuilder.le(itemRoot.get("price"), price)));}//itemStock 大于等于 >= 语句if (stock != null) {predicatesList.add(criteriaBuilder.and(criteriaBuilder.ge(itemRoot.get("stock"), stock)));}//where() 拼接查询条件query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));//返回通过 CriteriaQuery 拼装的 Predicatereturn query.getRestriction();});}
- 而没有 Spring Data JPA 封装之前,如果想获得此三个对象 Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder,老式 Hibernate 的写法如下(PS:强烈不推荐哦,虽然现在也支持,只是让大家知道了解一下。):
@Autowired //导入entityManagerprivate EntityManager entityManager;
//创建CriteriaBuilder安全查询工厂,CriteriaBuilder是一个工厂对象,安全查询的开始.用于构建JPA安全查询.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
//创建CriteriaQuery安全查询主语句
//CriteriaQuery对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。
CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
//Root 定义查询的From子句中能出现的类型
Root<Item> itemRoot = query.from(Item.class);
- 我们再来看一个利用 CriteriaQuery 例子,其实大家可以扩展一下思路,就是 Hibernate 那套在这里面都支持,不过作者还是建议代码越简单越好。
List<UserSpuFavoriteEntity> result = userSpuFavoriteDao.findAll((Root<UserSpuFavoriteEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{query.where(cb.and(cb.equal(root.get("userName"), userName),cb.isFalse(root.get("isDelete"))));query.orderBy(cb.desc(root.get("updateTime")));return query.getRestriction();});