JPA中,QBC查询,JpaSpecificationExecutor,Specification总结

本文详细介绍了如何在Java中使用JPA的CriteriaBuilder和CriteriaQuery进行数据库查询,包括条件构造、多表关联、字段选择、分组、排序以及分页等操作。
摘要由CSDN通过智能技术生成
class Specification {
    public static void main(String[] args) {
        // 底层实现原理,Specification接口底层就是利用EntityManager实现
        EntityManager entityManager = SpringUtil.getBean(EntityManager.class);
        // 固定套路,总共十一步

        // 第一步: 获取条件构造器
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

        // 第二步: 构造标准查询API,这里使用Object[]而不是使用User是因为下面有别名,函数的情况,所以用实体无法接收,还有很多的方式
        CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);

        // 第三步: 指定查询的根实体,说白了就是主表内容,Root就表示主表的字段信息
        Root<User> root = criteriaQuery.from(User.class);

        // 第四步(可选): 多表关联,User表与IdCard表关联,使用的都是属性名,自动设置连接条件
        Join<User, IdCard> join = root.join("idCard", JoinType.LEFT);

        // 如果设置一对多,或者多对多,使用joinCollection
        // Join<User, Address> join = root.joinCollection("idCard", JoinType.LEFT);

        // 第四-五步: 要查询的字段汇总
        // 查询所有
        // criteriaQuery.select(root);
        // 查询指定字段和使用聚合函数并且取别名

        // 给字段取别名,记得接受结果的返回值的属性需要对应上
        // 注意: 控制台打印的SQL没有取别名,Hibernate生成的SQL语句不会包含Criteria API中设置的别名
        Selection<String> name = root.get("name").as(String.class).alias("name");
        Selection<Integer> age = root.get("age").as(Integer.class).alias("age");
        // 给聚合函数取别名
        Expression<Long> count = criteriaBuilder.count(root.get("age"));
        criteriaBuilder.construct(Long.class, count.alias("count"));
        // 查询字段,其中,root表示主表select root.*,join表示关联表select join.*
        criteriaQuery.multiselect(root, join, name, age, count);

        // 第五步: 构建条件并设置条件,tip: 下面criteriaQuery操作实际上不区分先后顺序
        // 如果要设置主表的字段条件,使用root.get("字段名")
        // 如果要设置关联表的字段条件,join.get("字段名")
        Predicate rootIsDelete = criteriaBuilder.isFalse(join.get("deleted"));
        Predicate idCardDelete = criteriaBuilder.isFalse(root.get("deleted"));
        // 如果要使用and,或or,直接使用conjunction,disjunction,构建一个空条件Predicate,然后在进行拼接和and,or方法是一样的
        Predicate andEmptyPredicate = criteriaBuilder.conjunction();
        // 构造条件
        Predicate nameEqualPredicate = criteriaBuilder.equal(root.get("name"), "luck");
        Predicate ageGePredicate = criteriaBuilder.ge(root.get("age"), 10);
        // 将构造条件统一存入到空的Predicate,并且他们使用and连接
        // user.name = 'luck' and user.age >= 10
        andEmptyPredicate.getExpressions().add(nameEqualPredicate);
        andEmptyPredicate.getExpressions().add(ageGePredicate);

        // 上面两行代码等于下面一行代码
        // user.name = 'luck' and user.age >= 10
        Predicate andPredicate = criteriaBuilder.and(nameEqualPredicate, ageGePredicate);

        // 将构造条件统一存入到空的Predicate,并且他们使用or连接
        // user.name = 'luck' or user.age >= 10
        Predicate orEmptyPredicate = criteriaBuilder.disjunction();
        orEmptyPredicate.getExpressions().add(nameEqualPredicate);
        orEmptyPredicate.getExpressions().add(ageGePredicate);

        // 上面两行代码等于下面一行代码
        // user.name = 'luck' or user.age >= 10
        Predicate orPredicate = criteriaBuilder.or(nameEqualPredicate, ageGePredicate);

        // 如果要实现 (x1) or (x2)这种情况,那么x1和x2都是一个使用and连接的Predicate,然后x1和x2使用or连接
        Predicate twoAndOrPredicate = criteriaBuilder.or(andPredicate, andEmptyPredicate);
        // 嵌套也是一样的(x1 or x2) and (x3 or x4)
        // 步骤1: x1和x2对应Predicate使用or进行连接,结果为x1x2
        // 步骤2: x3和x4对应Predicate使用or进行连接,结果为x3x4
        // 步骤3: 再将步骤一结果和步骤二结果x1x2与x3x4使用and进行连接得到x1x2Andx3x4,最终作为结果
        // (user.name = ? or username = ?) and (user.age >= 100 or user.age < 10)
        Predicate x1 = criteriaBuilder.equal(root.get("name"), "luck");
        Predicate x2 = criteriaBuilder.equal(root.get("name"), "java");
        Predicate x1x2 = criteriaBuilder.or(x1, x2);
        Predicate x3 = criteriaBuilder.ge(root.get("age"), 100);
        Predicate x4 = criteriaBuilder.lt(root.get("age"), 10);
        Predicate x3x4 = criteriaBuilder.or(x3, x4);
        Predicate x1x2Andx3x4 = criteriaBuilder.and(x1x2, x3x4);

        // 以上所有构建的条件都可以使用上,这个就是为了说明sql,上面构造的条件意义不大
        criteriaQuery.where(rootIsDelete, idCardDelete, orPredicate, twoAndOrPredicate, x1x2Andx3x4);

        // 第六步(可选): 构造分组条件并设置
        // 指定字段分组,可以有多个
        criteriaQuery.groupBy(root.get("age"));

        // 第七步(可选): 构造分组后条件并设置
        // 这个和上面讲的where一样
        criteriaQuery.having();

        // 第八步(可选): 构造排序条件并设置
        // 指定排序字段,并且设置排序方式
        criteriaQuery.orderBy(criteriaBuilder.asc(root.get("age")));

        // 第九步: 使用标准查询API(CriteriaQuery)构建一个可执行标准查询的Query对象
        TypedQuery<Object[]> query = entityManager.createQuery(criteriaQuery);

        // 第十步(可选): 设置分页参数,limit 1,10
        query.setFirstResult(1).setMaxResults(10);

        // 第十一步: 执行查询,获取结果
        List<Object[]> users = query.getResultList();
        for (Object[] user : users) {
            for (Object u : user) {
                System.out.print(u + ",");
            }
            System.out.println();
        }
        System.out.println(users);

    }
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用JPA的Projection机制进行指定字段查询。具体实现可以参考以下代码示例: ```java public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { List<UserProjection> findAllBy(Specification<User> specification); interface UserProjection { Long getId(); String getUsername(); } } ``` 在这个示例,我们定义了一个Repository接口,并继承了JpaRepository和JpaSpecificationExecutor接口。其JpaSpecificationExecutor接口提供了Specification查询规范,可以根据条件查询实体类数据。 通过定义一个UserProjection接口,我们可以使用JPA的Projection机制指定实体类的特定字段(例如:id和username)。 在findAllBy方法,我们使用Specification查询规范,并返回UserProjection类型的数据列表。 使用该方法实现指定字段查询的示例代码如下: ```java @Autowired private UserRepository userRepository; public List<UserRepository.UserProjection> findUserByUsername(String username) { return userRepository.findAllBy((root, query, criteriaBuilder) -> { query.select(criteriaBuilder.construct( UserRepository.UserProjection.class, root.get("id"), root.get("username") )); return criteriaBuilder.equal(root.get("username"), username); }); } ``` 在这个示例,我们根据指定的username查询UserProjection类型的数据列表,其Query.select方法传递了UserProjection的构造器参数列表,用于指定查询的字段。指定完查询的字段后,我们使用equal方法创建查询条件,并对UserRepository进行调用,完成查询操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值