Querydsl-JPA learning (Advanced chapter)

1 Introduction:

The first part of the article we Querydsl-JPA for the introduction and basic explanations, down began to introduce some of the usual multi-table we often use joint investigation with how Querydsl-JPA is achieved.

2. Basic script:

2.1: user information table

-- Create table
create table USER_TMW
(
  id         VARCHAR2(32 CHAR) not null,
  name       VARCHAR2(32 CHAR),
  age        NUMBER(19,2),
  money      NUMBER(19,2),
  begin_time VARCHAR2(32 CHAR),
  end_time   VARCHAR2(32 CHAR),
  dept_id    VARCHAR2(32 CHAR)
)
-- Create/Recreate primary, unique and foreign key constraints 
alter table USER_TMW
  add primary key (ID)
  using index 
  tablespace UFGOV
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
复制代码
insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('8a84a8b36bbbc8e1016bbbd803c60016', '老王', 20.00, 2000.00, '1567579914276', '1567579904276', 'C8477CE676B143E983260B45D05C06B3');

insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('0000000000000000000111', '小王', 30.00, 1500.00, '1567579924276', '1567579904276', 'C8477CE676B143E983260B45D05C06B3');

insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('0000000000000000000001', '王五', 18.00, 1800.00, '1567579934276', '1567579904276', '8a90959d6b88ce95016b8c547cfb03e7');

insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('0000000000000000000011', '小刚', 25.00, 1000.00, '1567579944276', '1567579904276', '8a90959d6b88ce95016b8c547cfb03e7');

insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('0000000000000000011111', '张三', 30.00, 2000.00, '1567579954276', '1567579904276', '8a90959d6b92c60e016b937f0d550080');

insert into user_tmw (ID, NAME, AGE, MONEY, BEGIN_TIME, END_TIME, DEPT_ID)
values ('0000000000000000000021', '李四', 30.00, 3000.00, '1567579964276', '1567579904276', '8a90959d6b92c60e016b937f0d550080');
复制代码

2.2: Segment Information table

-- Create table
create table DEPT_TMW
(
  id          VARCHAR2(32 CHAR) not null,
  dept_name   VARCHAR2(32 CHAR),
  dept_no     VARCHAR2(32 CHAR),
  create_time VARCHAR2(32 CHAR),
  p_dept_id   VARCHAR2(32 CHAR)
)
-- Create/Recreate primary, unique and foreign key constraints 
alter table DEPT_TMW
  add primary key (ID)
  using index 
  tablespace UFGOV
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
复制代码
insert into dept_tmw (ID, DEPT_NAME, DEPT_NO, CREATE_TIME, P_DEPT_ID)
values ('C8477CE676B143E983260B45D05C06B3', '研发部门', 'N001', '1567579904276', null);

insert into dept_tmw (ID, DEPT_NAME, DEPT_NO, CREATE_TIME, P_DEPT_ID)
values ('8a90959d6b88ce95016b8c547cfb03e7', '测试部门', 'N002', '1567579804276', 'C8477CE676B143E983260B45D05C06B3');

insert into dept_tmw (ID, DEPT_NAME, DEPT_NO, CREATE_TIME, P_DEPT_ID)
values ('8a90959d6b92c60e016b937f0d550080', '运维部门', 'N003', '1567579704276', '8a90959d6b88ce95016b8c547cfb03e7');
复制代码

3.Querydsl-JPA multi-table operation:

3.1: New entity class users and departments

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

/**
 * @ProjectName: queryDsl
 * @Package: com.springboot.demo.bean
 * @ClassName: Dept
 * @Author: tianmengwei
 * @Description:
 * @Date: 2019/9/4 15:10
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "dept_tmw")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Dept {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-uuid")
    @GenericGenerator(name = "custom-uuid", strategy = "com.springboot.demo.bean.CustomUUIDGenerator")
    @Column(name = "id", nullable = false, length = 32)
    private String id;

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

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

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

    @Column(name = "p_dept_id")
    private String pDeptId;
}
复制代码
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.math.BigDecimal;

/**
 * @ProjectName: queryDsl
 * @Package: com.springboot.demo
 * @ClassName: User
 * @Author: tianmengwei
 * @Description:
 * @Date: 2019/8/19 19:35
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "user_tmw")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-uuid")
    @GenericGenerator(name = "custom-uuid", strategy = "com.springboot.demo.bean.CustomUUIDGenerator")
    @Column(name = "id", nullable = false, length = 32)
    private String id;

    @Column(name = "name", length = 10)
    private String name;

    @Column(name = "age")
    private Integer age;

    @Column(name = "money")
    private BigDecimal money;

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

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

    @Column(name = "dept_id")
    private String deptId;
}
复制代码

3.2: multi-table associated with the query result display processing multi-field stitching (the concat ())

public void getDeptUserListByLeftJoin() {
    QDept qDept = QDept.dept;
    QUser qUser = QUser.user;
    List<Tuple> tupleList = jpaQueryFactory.select(qDept.deptNo.concat(":").concat(qDept.deptName).concat(":").concat(qUser.name),
            qUser.age, qUser.money).from(qDept).leftJoin(qUser).on(qDept.id.eq(qUser.deptId))
            .orderBy(qUser.age.desc()).fetch();
    List<Map<String, Object>> resultList = tupleList.stream().map(x -> {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("nameDept", x.get(0, Dept.class));
        resultMap.put("nameUser", x.get(0, User.class));
        resultMap.put("nameDeptUser", x.get(qDept.deptNo.concat(":").concat(qDept.deptName).concat(":").concat(qUser.name)));
        resultMap.put("age", x.get(qUser.age));
        resultMap.put("money", x.get(qUser.money));
        return resultMap;
    }).collect(Collectors.toList());
    String userQueryResultsStr = JSON.toJSONString(resultList);
    System.out.println("getDeptUserListByLeftJoin的结果集:" + userQueryResultsStr);
}
复制代码

Here, we get in return results based on the type jpaFactory associated with the query returns Tuple, Tuple provides the following two ways, you can specify an index based on property and to acquire:

In the method an entity class index of the second parameter acquired is designated a Class, relational query written herein can be any of the test.

3.3: related query results in the case when the use of querydsl

Here querydsl provides CaseBuilder class, we can use this class value for the field to do the conversion process, of course, we can also deal with it in time with the stream flow;

public void getDeptUserListByJoin() {
    QDept qDept = QDept.dept;
    QUser qUser = QUser.user;
    StringExpression otherwise = new CaseBuilder().when(qUser.age.gt(18)).then("成年人").when(qUser.age.lt(18)).then("青少年")
            .otherwise("快成年了");

    List<Tuple> tupleList = jpaQueryFactory.select(qUser.name,
            otherwise, qUser.age, qUser.money).from(qDept).join(qUser).on(qDept.id.eq(qUser.deptId))
            .orderBy(qUser.age.desc()).fetch();
    List<Map<String, Object>> resultList = tupleList.stream().map(x -> {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("name", x.get(qUser.name));
        resultMap.put("age", x.get(1, User.class));
        return resultMap;
    }).collect(Collectors.toList());

    String userQueryResultsStr = JSON.toJSONString(resultList);
    System.out.println("getDeptUserListByJoin的结果集:" + userQueryResultsStr);
}
复制代码

3.4: Querydsl subquery use:

Here Querydsl provides JPAExpressions class, we use the class to do a sub query processing.

public void getMaxMoneyUserInfo() {
QUser qUser = QUser.user;
List<User> userList = jpaQueryFactory.selectFrom(qUser)
        .where(qUser.money.eq(JPAExpressions.select(qUser.money.max()).from(qUser))).fetch();
String userQueryResultsStr = JSON.toJSONString(userList);
System.out.println("getMaxMoneyUserInfo的结果集:" + userQueryResultsStr);
}
复制代码

3.5: Querydsl from the query using:

Here we are dealing with a similar query from sql written as an alias certainly not the same, so we create two Q version of the entity class object created by querydsl time, Q version of the entity class provides configuration parameters have, you can specify an alias .

public void getDeptParentInfo() {
    //select t.dept_name,t1.* from dept_tmw t right join dept_tmw t1 on t.id = t1.p_dept_id
    QDept dept1 = new QDept("dept1");
    QDept dept2 = new QDept("dept2");

    StringExpression otherwise = new CaseBuilder().when(dept1.deptName.isNull().or(dept1.deptName.isEmpty()))
            .then("总部")
            .otherwise(dept1.deptName);
    List<Tuple> fetch = jpaQueryFactory.select(otherwise.concat(":").concat(dept2.deptName), dept2.deptNo, dept2.createTime)
            .from(dept1).rightJoin(dept2).on(dept1.id.eq(dept2.pDeptId)).orderBy(dept2.deptNo.desc()).fetch();
    List<Map<String, Object>> collect = fetch.stream().map(x -> {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("name", x.get(0, Dept.class));
        resultMap.put("deptNo", x.get(dept2.deptNo));
        resultMap.put("createTime", x.get(dept2.createTime));
        return resultMap;
    }).collect(Collectors.toList());
    String userQueryResultsStr = JSON.toJSONString(collect);
    System.out.println("getDeptParentInfo的结果集:" + userQueryResultsStr);
}
复制代码

3.6: Query time interval within Querydsl range of users:

Here is the value of time transfer timestamp string, the range interval value to convert the string values ​​for query.

public void getUserListByBetweenCreateTime() {
    QUser qUser = QUser.user;
    List<User> fetch = jpaQueryFactory.selectFrom(qUser).where(qUser.beginTime.between("1567579924276", "1567579954276")).fetch();
    String userQueryResultsStr = JSON.toJSONString(fetch);
    System.out.println("getUserListByBetweenCreateTime的结果集:" + userQueryResultsStr);
}
复制代码

4. Querydsl and spring web integration:

Here provide spring-data can be converted annotation @QuerydslPredicate http request parameters for the Predicate;

The following code follows the link by visiting:
HTTP: // localhost:? 8080 / the User / Seach Age = 30 & money = 3000
query result is the age of 30 and money for the 3000 users, but the specific other fuzzy queries, range queries unknown.

import com.querydsl.core.types.Predicate;
import com.springboot.demo.bean.User;
import com.springboot.demo.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/seach", method = RequestMethod.GET)
    @ResponseBody
    //http://localhost:8080/ar/user/seach?age=30&money=3000
    public Iterable<User> getUsers(
                 @QuerydslPredicate(root = User.class) Predicate predicate) {
        Iterable<User> list = userDao.findAll(predicate);
        return list;
    }
}
复制代码
import com.springboot.demo.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;

public interface UserDao extends JpaRepository<User, String>, JpaSpecificationExecutor<User>, QuerydslPredicateExecutor<User> {
}
复制代码

5. Summary:

Through the study of knowledge of querydsl-jpa, compared to the spring-data-jpa, we use querydsl-jpa in dealing with complex multi-table queries and relevance, it can make the code more readable, while the use of spring-data-jpa provided dao inherited interface layer: JpaRepository and JpaSpecificationExecutor let us single-table query more concise, so we can combine the use in practical applications, whichever advantages to its dregs.

Guess you like

Origin juejin.im/post/5d708697e51d4561c02a2592