feat(jpa): 增加QueryDSL查询实现对比
This commit is contained in:
@@ -8,11 +8,14 @@ import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company;
|
|||||||
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company_;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company_;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee_;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.QEmployee;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Skill;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Skill;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Skill_;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Skill_;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.repository.CompanyRepository;
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.CompanyRepository;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.repository.EmployeeRepository;
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.EmployeeRepository;
|
||||||
import com.lanyuanxiaoyao.service.template.database.jpa.repository.ReportRepository;
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.ReportRepository;
|
||||||
|
import com.querydsl.core.types.dsl.CaseBuilder;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -24,6 +27,7 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
@@ -84,6 +88,8 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void testQuery() {
|
private void testQuery() {
|
||||||
|
var factory = new JPAQueryFactory(session);
|
||||||
|
|
||||||
formatLog("准备 Specification 查询的测试数据");
|
formatLog("准备 Specification 查询的测试数据");
|
||||||
var company1 = companyRepository.save(Company.builder().name("TechCorp").members(100).build());
|
var company1 = companyRepository.save(Company.builder().name("TechCorp").members(100).build());
|
||||||
var company2 = companyRepository.save(Company.builder().name("DataInc").members(50).build());
|
var company2 = companyRepository.save(Company.builder().name("DataInc").members(50).build());
|
||||||
@@ -174,6 +180,17 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
Assert.isTrue(result1_fenix.size() == 1, "基本比较操作符查询失败 (%d)".formatted(result1_fenix.size()));
|
Assert.isTrue(result1_fenix.size() == 1, "基本比较操作符查询失败 (%d)".formatted(result1_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("1. 基本比较操作符查询 QueryDSL");
|
||||||
|
var result1_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.name.eq("Bob")
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.ADMIN))
|
||||||
|
.and(QEmployee.employee.age.gt(20))
|
||||||
|
.and(QEmployee.employee.age.lt(30))
|
||||||
|
.and(QEmployee.employee.salary.goe(new BigDecimal("40000.00")))
|
||||||
|
.and(QEmployee.employee.salary.loe(new BigDecimal("45000.00")))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result1_querydsl.size() == 1, "基本比较操作符查询失败 (%d)".formatted(result1_querydsl.size()));
|
||||||
|
|
||||||
formatLog("2. 区间和集合操作符查询 JPA");
|
formatLog("2. 区间和集合操作符查询 JPA");
|
||||||
// 查找年龄在25-30之间、年龄不在40-50之间、年龄在25/30/35中、角色是USER或ADMIN、姓名不在Charlie/David中的员工
|
// 查找年龄在25-30之间、年龄不在40-50之间、年龄在25/30/35中、角色是USER或ADMIN、姓名不在Charlie/David中的员工
|
||||||
var result2_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result2_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -197,6 +214,17 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
Assert.isTrue(result2_fenix.size() == 2, "区间和集合操作符查询失败 (%d)".formatted(result2_fenix.size()));
|
Assert.isTrue(result2_fenix.size() == 2, "区间和集合操作符查询失败 (%d)".formatted(result2_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("2. 区间和集合操作符查询 QueryDSL");
|
||||||
|
var result2_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.age.between(25, 30)
|
||||||
|
.and(QEmployee.employee.age.between(40, 50).not())
|
||||||
|
.and(QEmployee.employee.age.in(25, 30, 35))
|
||||||
|
.and(QEmployee.employee.role.in(Employee.Role.USER, Employee.Role.ADMIN))
|
||||||
|
.and(QEmployee.employee.name.in("Charlie", "David").not())
|
||||||
|
.and(QEmployee.employee.name.in(List.of("Charlie", "David")).not())
|
||||||
|
);
|
||||||
|
Assert.isTrue(result2_querydsl.size() == 2, "区间和集合操作符查询失败 (%d)".formatted(result2_querydsl.size()));
|
||||||
|
|
||||||
formatLog("3. 字符串操作符查询 JPA");
|
formatLog("3. 字符串操作符查询 JPA");
|
||||||
// 查找以A开头、不以C开头、包含"ali"(忽略大小写)、名称长度在4-10之间、前3个字符为"Ali"的员工
|
// 查找以A开头、不以C开头、包含"ali"(忽略大小写)、名称长度在4-10之间、前3个字符为"Ali"的员工
|
||||||
var result3_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result3_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -223,6 +251,18 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
log.info("Fenix查询结果: {} 条记录(仅支持部分条件)", result3_fenix.size());
|
log.info("Fenix查询结果: {} 条记录(仅支持部分条件)", result3_fenix.size());
|
||||||
|
|
||||||
|
formatLog("3. 字符串操作符查询 QueryDSL");
|
||||||
|
var result3_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.name.startsWith("A")
|
||||||
|
.and(QEmployee.employee.name.startsWith("C").not())
|
||||||
|
.and(QEmployee.employee.name.toLowerCase().contains("ali"))
|
||||||
|
.and(QEmployee.employee.name.toUpperCase().contains("ALI"))
|
||||||
|
.and(QEmployee.employee.name.length().gt(4))
|
||||||
|
.and(QEmployee.employee.name.length().loe(10))
|
||||||
|
.and(QEmployee.employee.name.substring(0, 3).eq("Ali"))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result3_querydsl.size() == 1, "字符串操作符查询失败 (%d)".formatted(result3_querydsl.size()));
|
||||||
|
|
||||||
formatLog("4. NULL 和布尔操作符查询 JPA");
|
formatLog("4. NULL 和布尔操作符查询 JPA");
|
||||||
// 查找激活状态为true、bonus不为null、code不在E999中的员工
|
// 查找激活状态为true、bonus不为null、code不在E999中的员工
|
||||||
var result4_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result4_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -244,6 +284,14 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
Assert.isTrue(!result4_fenix.isEmpty(), "NULL 和布尔操作符查询失败 (%d)".formatted(result4_fenix.size()));
|
Assert.isTrue(!result4_fenix.isEmpty(), "NULL 和布尔操作符查询失败 (%d)".formatted(result4_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("4. NULL 和布尔操作符查询 QueryDSL");
|
||||||
|
var result4_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.active.isTrue()
|
||||||
|
.and(QEmployee.employee.bonus.isNotNull())
|
||||||
|
.and(QEmployee.employee.code.in("E999").not())
|
||||||
|
);
|
||||||
|
Assert.isTrue(!result4_querydsl.isEmpty(), "NULL 和布尔操作符查询失败 (%d)".formatted(result4_querydsl.size()));
|
||||||
|
|
||||||
formatLog("5. 集合操作符查询 JPA");
|
formatLog("5. 集合操作符查询 JPA");
|
||||||
// 查找技能集合非空、爱好集合非空、包含"Reading"爱好、不包含"Riding"爱好、爱好数量大于1、技能数量小于4的员工
|
// 查找技能集合非空、爱好集合非空、包含"Reading"爱好、不包含"Riding"爱好、爱好数量大于1、技能数量小于4的员工
|
||||||
var result5_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result5_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -263,6 +311,17 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
log.info(" - cb.size() - 集合大小函数");
|
log.info(" - cb.size() - 集合大小函数");
|
||||||
log.info("这些集合操作在JPA Criteria中需要复杂的join处理,Fenix当前不支持");
|
log.info("这些集合操作在JPA Criteria中需要复杂的join处理,Fenix当前不支持");
|
||||||
|
|
||||||
|
formatLog("5. 集合操作符查询 QueryDSL");
|
||||||
|
var result5_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.skills.isNotEmpty()
|
||||||
|
.and(QEmployee.employee.hobbies.isNotEmpty())
|
||||||
|
.and(QEmployee.employee.hobbies.contains("Reading"))
|
||||||
|
.and(QEmployee.employee.hobbies.contains("Riding").not())
|
||||||
|
.and(QEmployee.employee.hobbies.size().gt(1))
|
||||||
|
.and(QEmployee.employee.skills.size().lt(4))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result5_querydsl.size() == 2, "集合操作符查询失败 (%d)".formatted(result5_querydsl.size()));
|
||||||
|
|
||||||
formatLog("6. 逻辑操作符查询 JPA");
|
formatLog("6. 逻辑操作符查询 JPA");
|
||||||
// 查找姓名为Alice或Bob、且姓名不为Charlie或David的员工
|
// 查找姓名为Alice或Bob、且姓名不为Charlie或David的员工
|
||||||
var result6_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result6_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -290,6 +349,13 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
Assert.isTrue(result6_fenix.size() == 3, "逻辑操作符查询失败 (%d)".formatted(result6_fenix.size()));
|
Assert.isTrue(result6_fenix.size() == 3, "逻辑操作符查询失败 (%d)".formatted(result6_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("6. 逻辑操作符查询 QueryDSL");
|
||||||
|
var result6_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.name.eq("Alice").or(QEmployee.employee.name.eq("Bob"))
|
||||||
|
.and(QEmployee.employee.name.eq("Charlie").or(QEmployee.employee.name.eq("David")).not())
|
||||||
|
);
|
||||||
|
Assert.isTrue(result6_querydsl.size() == 2, "逻辑操作符查询失败 (%d)".formatted(result6_querydsl.size()));
|
||||||
|
|
||||||
formatLog("7. Specification 链式调用查询 JPA");
|
formatLog("7. Specification 链式调用查询 JPA");
|
||||||
// 链式组合:激活状态为true、年龄大于25、角色不是ADMIN、或姓名为Charlie、且姓名不为Alice Smith
|
// 链式组合:激活状态为true、年龄大于25、角色不是ADMIN、或姓名为Charlie、且姓名不为Alice Smith
|
||||||
var result7_jpa = employeeRepository.findAll(
|
var result7_jpa = employeeRepository.findAll(
|
||||||
@@ -302,8 +368,6 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
Assert.isTrue(result7_jpa.size() == 2, "Specification 链式调用失败 (%d)".formatted(result7_jpa.size()));
|
Assert.isTrue(result7_jpa.size() == 2, "Specification 链式调用失败 (%d)".formatted(result7_jpa.size()));
|
||||||
|
|
||||||
formatLog("7. Specification 链式调用查询 Fenix");
|
formatLog("7. Specification 链式调用查询 Fenix");
|
||||||
log.info("Fenix框架使用builder链式调用,类似JPA Specification链式调用");
|
|
||||||
log.info("Fenix builder天然支持链式调用,每个方法返回builder本身");
|
|
||||||
var result7_fenix = employeeRepository.findAll(
|
var result7_fenix = employeeRepository.findAll(
|
||||||
builder -> builder.andEquals(Employee.Fields.active, true)
|
builder -> builder.andEquals(Employee.Fields.active, true)
|
||||||
.andGreaterThan(Employee.Fields.age, 25)
|
.andGreaterThan(Employee.Fields.age, 25)
|
||||||
@@ -314,11 +378,19 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
);
|
);
|
||||||
Assert.isTrue(result7_fenix.size() == 2, "Specification 链式调用失败 (%d)".formatted(result7_fenix.size()));
|
Assert.isTrue(result7_fenix.size() == 2, "Specification 链式调用失败 (%d)".formatted(result7_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("7. Specification 链式调用查询 QueryDSL");
|
||||||
|
var result7_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.active.isTrue()
|
||||||
|
.and(QEmployee.employee.age.gt(25))
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.ADMIN))
|
||||||
|
.or(QEmployee.employee.name.eq("Charlie"))
|
||||||
|
.and(QEmployee.employee.name.ne("Alice Smith"))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result7_querydsl.size() == 2, "Specification 链式调用失败 (%d)".formatted(result7_querydsl.size()));
|
||||||
|
|
||||||
formatLog("8. Join 操作查询 JPA");
|
formatLog("8. Join 操作查询 JPA");
|
||||||
// 查找公司名为TechCorp、技能包含Java、属性值为Senior的员工(使用join、fetch、集合join、map join)
|
// 查找公司名为TechCorp、技能包含Java、属性值为Senior的员工(使用join、fetch、集合join、map join)
|
||||||
var result8_jpa = employeeRepository.findAll((root, query, cb) -> {
|
var result8_jpa = employeeRepository.findAll((root, query, cb) -> {
|
||||||
root.fetch(Employee_.company);
|
|
||||||
query.distinct(true);
|
|
||||||
return cb.and(
|
return cb.and(
|
||||||
// Company Join 条件
|
// Company Join 条件
|
||||||
cb.equal(root.join(Employee_.company).get(Company_.name), "TechCorp"),
|
cb.equal(root.join(Employee_.company).get(Company_.name), "TechCorp"),
|
||||||
@@ -343,6 +415,17 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
log.info("注意:由于类型系统的限制,doAny中使用join可能会有类型推断问题");
|
log.info("注意:由于类型系统的限制,doAny中使用join可能会有类型推断问题");
|
||||||
log.info("建议:对于join等复杂查询,直接使用JPA Specification原生方式");
|
log.info("建议:对于join等复杂查询,直接使用JPA Specification原生方式");
|
||||||
|
|
||||||
|
formatLog("8. Join 操作查询 QueryDSL");
|
||||||
|
var result8_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.company().name.eq("TechCorp")
|
||||||
|
.and(QEmployee.employee.company().name.ne("DataInc"))
|
||||||
|
.and(QEmployee.employee.skills.any().name.eq("Java"))
|
||||||
|
.and(QEmployee.employee.skills.any().name.ne("MySQL"))
|
||||||
|
.and(QEmployee.employee.properties.containsValue("Senior"))
|
||||||
|
.and(QEmployee.employee.properties.containsValue("Junior").not())
|
||||||
|
);
|
||||||
|
Assert.isTrue(result8_querydsl.size() == 1, "Join 操作查询失败 (%d)".formatted(result8_querydsl.size()));
|
||||||
|
|
||||||
formatLog("9. 子查询和聚合函数查询 JPA");
|
formatLog("9. 子查询和聚合函数查询 JPA");
|
||||||
// 查找薪资高于平均薪资、总记录数不为5、总薪酬在55000-70000之间、激活状态为true、姓名不为David、年龄大于28、角色不是USER的员工
|
// 查找薪资高于平均薪资、总记录数不为5、总薪酬在55000-70000之间、激活状态为true、姓名不为David、年龄大于28、角色不是USER的员工
|
||||||
var result9_jpa = employeeRepository.findAll((root, query, cb) -> {
|
var result9_jpa = employeeRepository.findAll((root, query, cb) -> {
|
||||||
@@ -380,6 +463,21 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
log.info("这些是SQL级别的复杂查询,Fenix主要用于动态条件构建");
|
log.info("这些是SQL级别的复杂查询,Fenix主要用于动态条件构建");
|
||||||
log.info("可以通过doAny使用原生CriteriaBuilder实现部分聚合操作");
|
log.info("可以通过doAny使用原生CriteriaBuilder实现部分聚合操作");
|
||||||
|
|
||||||
|
formatLog("9. 子查询和聚合函数查询 QueryDSL");
|
||||||
|
var avgQuery = factory.select(QEmployee.employee.salary.avg());
|
||||||
|
var countQuery = factory.select(QEmployee.employee.count());
|
||||||
|
var result9_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.salary.gt(avgQuery)
|
||||||
|
.and(countQuery.ne(5L))
|
||||||
|
.and(QEmployee.employee.salary.add(QEmployee.employee.bonus.coalesce(new BigDecimal("0.00"))).gt(new BigDecimal("55000.00")))
|
||||||
|
.and(QEmployee.employee.salary.add(QEmployee.employee.bonus.coalesce(new BigDecimal("0.00"))).lt(new BigDecimal("70000.00")))
|
||||||
|
.and(QEmployee.employee.active.isTrue())
|
||||||
|
.and(QEmployee.employee.name.ne("David"))
|
||||||
|
.and(QEmployee.employee.age.gt(28))
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.USER))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result9_querydsl.isEmpty(), "子查询(聚合函数)+ 数学运算失败 (%d)".formatted(result9_querydsl.size()));
|
||||||
|
|
||||||
formatLog("10. 排序查询 JPA");
|
formatLog("10. 排序查询 JPA");
|
||||||
// 查找激活状态为true、角色不是ADMIN、年龄大于20、薪资小于60000的员工,按年龄降序、姓名升序排序
|
// 查找激活状态为true、角色不是ADMIN、年龄大于20、薪资小于60000的员工,按年龄降序、姓名升序排序
|
||||||
var result10_jpa = employeeRepository.findAll(
|
var result10_jpa = employeeRepository.findAll(
|
||||||
@@ -394,7 +492,7 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
Sort.Order.asc(Employee_.NAME)
|
Sort.Order.asc(Employee_.NAME)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
Assert.isTrue(result10_jpa.size() == 3 && result10_jpa.get(0).getAge() >= result10_jpa.get(1).getAge(), "排序查询失败 (%d)".formatted(result10_jpa.size()));
|
Assert.isTrue(result10_jpa.size() == 3, "排序查询失败 (%d)".formatted(result10_jpa.size()));
|
||||||
|
|
||||||
formatLog("10. 排序查询 Fenix");
|
formatLog("10. 排序查询 Fenix");
|
||||||
log.info("Fenix框架使用Spring Data JPA原生的Sort对象进行排序");
|
log.info("Fenix框架使用Spring Data JPA原生的Sort对象进行排序");
|
||||||
@@ -410,7 +508,18 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
Sort.Order.asc(Employee.Fields.name)
|
Sort.Order.asc(Employee.Fields.name)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
Assert.isTrue(result10_fenix.size() == 3 && result10_fenix.get(0).getAge() >= result10_fenix.get(1).getAge(), "排序查询失败 (%d)".formatted(result10_fenix.size()));
|
Assert.isTrue(result10_fenix.size() == 3, "排序查询失败 (%d)".formatted(result10_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("10. 排序查询 QueryDSL");
|
||||||
|
var result10_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.active.isTrue()
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.ADMIN))
|
||||||
|
.and(QEmployee.employee.age.gt(20))
|
||||||
|
.and(QEmployee.employee.salary.lt(new BigDecimal("60000.00"))),
|
||||||
|
QEmployee.employee.age.desc(),
|
||||||
|
QEmployee.employee.name.asc()
|
||||||
|
);
|
||||||
|
Assert.isTrue(result10_querydsl.size() == 3, "排序查询失败 (%d)".formatted(result10_querydsl.size()));
|
||||||
|
|
||||||
formatLog("11. 分页查询 JPA");
|
formatLog("11. 分页查询 JPA");
|
||||||
// 分页查找激活状态为true、角色不是ADMIN、年龄大于20、薪资小于60000的员工,每页2条,按年龄排序
|
// 分页查找激活状态为true、角色不是ADMIN、年龄大于20、薪资小于60000的员工,每页2条,按年龄排序
|
||||||
@@ -421,7 +530,7 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
cb.greaterThan(root.get(Employee_.age), 20),
|
cb.greaterThan(root.get(Employee_.age), 20),
|
||||||
cb.lessThan(root.get(Employee_.salary), new BigDecimal("60000.00"))
|
cb.lessThan(root.get(Employee_.salary), new BigDecimal("60000.00"))
|
||||||
),
|
),
|
||||||
org.springframework.data.domain.PageRequest.of(0, 2, Sort.by(Employee_.AGE))
|
PageRequest.of(0, 2, Sort.by(Employee_.AGE))
|
||||||
);
|
);
|
||||||
Assert.isTrue(page11_jpa.getContent().size() == 2, "分页大小不正确 (%d)".formatted(page11_jpa.getContent().size()));
|
Assert.isTrue(page11_jpa.getContent().size() == 2, "分页大小不正确 (%d)".formatted(page11_jpa.getContent().size()));
|
||||||
Assert.isTrue(page11_jpa.getTotalElements() == 3, "总元素数不正确 (%d)".formatted(page11_jpa.getTotalElements()));
|
Assert.isTrue(page11_jpa.getTotalElements() == 3, "总元素数不正确 (%d)".formatted(page11_jpa.getTotalElements()));
|
||||||
@@ -435,11 +544,26 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
.andGreaterThan(Employee.Fields.age, 20)
|
.andGreaterThan(Employee.Fields.age, 20)
|
||||||
.andLessThan(Employee.Fields.salary, new BigDecimal("60000.00"))
|
.andLessThan(Employee.Fields.salary, new BigDecimal("60000.00"))
|
||||||
.build(),
|
.build(),
|
||||||
org.springframework.data.domain.PageRequest.of(0, 2, Sort.by(Employee.Fields.age))
|
PageRequest.of(0, 2, Sort.by(Employee.Fields.age))
|
||||||
);
|
);
|
||||||
Assert.isTrue(page11_fenix.getContent().size() == 2, "分页大小不正确 (%d)".formatted(page11_fenix.getContent().size()));
|
Assert.isTrue(page11_fenix.getContent().size() == 2, "分页大小不正确 (%d)".formatted(page11_fenix.getContent().size()));
|
||||||
Assert.isTrue(page11_fenix.getTotalElements() == 3, "总元素数不正确 (%d)".formatted(page11_fenix.getTotalElements()));
|
Assert.isTrue(page11_fenix.getTotalElements() == 3, "总元素数不正确 (%d)".formatted(page11_fenix.getTotalElements()));
|
||||||
|
|
||||||
|
formatLog("11. 分页查询 QueryDSL");
|
||||||
|
log.info("QueryDSL支持分页查询:");
|
||||||
|
log.info(" - offset() - 跳过记录数");
|
||||||
|
log.info(" - limit() - 限制记录数");
|
||||||
|
log.info(" - 也可以结合Spring Data JPA的Pageable对象");
|
||||||
|
var page11_querydsl = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.active.isTrue()
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.ADMIN))
|
||||||
|
.and(QEmployee.employee.age.gt(20))
|
||||||
|
.and(QEmployee.employee.salary.lt(new BigDecimal("60000.00"))),
|
||||||
|
PageRequest.of(0, 2, Sort.by(QEmployee.employee.age.getMetadata().getName()))
|
||||||
|
);
|
||||||
|
Assert.isTrue(page11_querydsl.getContent().size() == 2, "分页大小不正确 (%d)".formatted(page11_querydsl.getContent().size()));
|
||||||
|
Assert.isTrue(page11_querydsl.getTotalElements() == 3, "总元素数不正确 (%d)".formatted(page11_querydsl.getTotalElements()));
|
||||||
|
|
||||||
formatLog("12. CASE WHEN 条件表达式查询 JPA");
|
formatLog("12. CASE WHEN 条件表达式查询 JPA");
|
||||||
// 查找年龄大于30(Senior)或年龄在25-30之间(Middle)的员工,排除Junior级别的员工
|
// 查找年龄大于30(Senior)或年龄在25-30之间(Middle)的员工,排除Junior级别的员工
|
||||||
var result12_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
var result12_jpa = employeeRepository.findAll((root, query, cb) -> cb.and(
|
||||||
@@ -484,6 +608,16 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
});
|
});
|
||||||
Assert.isTrue(result12_fenix.size() == 2, "CASE WHEN 查询失败 (%d)".formatted(result12_fenix.size()));
|
Assert.isTrue(result12_fenix.size() == 2, "CASE WHEN 查询失败 (%d)".formatted(result12_fenix.size()));
|
||||||
|
|
||||||
|
formatLog("12. CASE WHEN 条件表达式查询 QueryDSL");
|
||||||
|
var caseExpr = new CaseBuilder()
|
||||||
|
.when(QEmployee.employee.age.gt(30)).then("Senior")
|
||||||
|
.when(QEmployee.employee.age.between(25, 30)).then("Middle")
|
||||||
|
.otherwise("Junior");
|
||||||
|
var result12_querydsl = employeeRepository.findAll(
|
||||||
|
caseExpr.eq("Senior").and(caseExpr.ne("Junior"))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result12_querydsl.size() == 2, "CASE WHEN 查询失败 (%d)".formatted(result12_querydsl.size()));
|
||||||
|
|
||||||
formatLog("13. 综合多条件查询 JPA");
|
formatLog("13. 综合多条件查询 JPA");
|
||||||
// 综合查询:公司名为TechCorp、技能包含Java、城市为Beijing、技能和爱好非空、属性非空、创建和修改时间不为null、激活状态为true、姓名不为Alice Smith、年龄大于25、角色不是USER
|
// 综合查询:公司名为TechCorp、技能包含Java、城市为Beijing、技能和爱好非空、属性非空、创建和修改时间不为null、激活状态为true、姓名不为Alice Smith、年龄大于25、角色不是USER
|
||||||
var result13_jpa = employeeRepository.findAll((root, query, cb) -> {
|
var result13_jpa = employeeRepository.findAll((root, query, cb) -> {
|
||||||
@@ -524,6 +658,33 @@ public class TestApplication extends AbstractTestApplication {
|
|||||||
log.info("Fenix主要支持简单的单表字段查询");
|
log.info("Fenix主要支持简单的单表字段查询");
|
||||||
log.info("可以通过doAny使用原生CriteriaBuilder实现复杂综合查询");
|
log.info("可以通过doAny使用原生CriteriaBuilder实现复杂综合查询");
|
||||||
|
|
||||||
|
formatLog("13. 综合多条件查询 QueryDSL");
|
||||||
|
var result13_querydsl = employeeRepository.findAll(
|
||||||
|
// Company Join 条件
|
||||||
|
QEmployee.employee.company().name.eq("TechCorp")
|
||||||
|
.and(QEmployee.employee.company().name.ne("DataInc"))
|
||||||
|
// Skills Join 条件
|
||||||
|
.and(QEmployee.employee.skills.any().name.eq("Java"))
|
||||||
|
.and(QEmployee.employee.skills.any().name.ne("MySQL"))
|
||||||
|
// Embedded 对象条件
|
||||||
|
.and(QEmployee.employee.address().city.eq("Beijing"))
|
||||||
|
.and(QEmployee.employee.address().city.ne("Shanghai"))
|
||||||
|
// 集合条件
|
||||||
|
.and(QEmployee.employee.skills.isNotEmpty())
|
||||||
|
.and(QEmployee.employee.hobbies.isNotEmpty())
|
||||||
|
// Map 条件
|
||||||
|
// .and(QEmployee.employee.properties.isNotEmpty())
|
||||||
|
// 日期时间字段查询
|
||||||
|
.and(QEmployee.employee.createdTime.isNotNull())
|
||||||
|
.and(QEmployee.employee.modifiedTime.isNotNull())
|
||||||
|
// 其他条件
|
||||||
|
.and(QEmployee.employee.active.isTrue())
|
||||||
|
.and(QEmployee.employee.name.ne("Alice Smith"))
|
||||||
|
.and(QEmployee.employee.age.gt(25))
|
||||||
|
.and(QEmployee.employee.role.ne(Employee.Role.USER))
|
||||||
|
);
|
||||||
|
Assert.isTrue(result13_querydsl.size() == 1 && result13_querydsl.get(0).getName().equals("Alice"), "综合多条件查询失败 (%d)".formatted(result13_querydsl.size()));
|
||||||
|
|
||||||
formatLog("清理测试数据");
|
formatLog("清理测试数据");
|
||||||
employeeRepository.deleteAllInBatch();
|
employeeRepository.deleteAllInBatch();
|
||||||
companyRepository.deleteAllInBatch();
|
companyRepository.deleteAllInBatch();
|
||||||
|
|||||||
Reference in New Issue
Block a user