1
0

feat(jpa): 增加QueryDSL查询实现对比

This commit is contained in:
2026-01-22 18:03:57 +08:00
parent 324d646b27
commit 611988d7ab

View File

@@ -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");
// 查找年龄大于30Senior或年龄在25-30之间Middle的员工排除Junior级别的员工 // 查找年龄大于30Senior或年龄在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();