同时使用 QuerydslBinderCustomizer 和 @QueryInit 的问题
Problem using QuerydslBinderCustomizer and @QueryInit at the same time
提供以下内容类
public class Department {
...
@OneToOne
@JoinColumn(name = "idDepartment")
@QueryInit("customer.company")
private Project project;
...
}
public class Project {
...
@OneToOne
@JoinColumn(name = "idCustomer")
private Customer customer;
...
}
public class Customer {
...
@OneToOne
@JoinColumn(name = "idCompany")
private Company company;
...
}
我需要在 project
上使用 @QueryInit
才能访问第 4 级或更高级别,如下所示:
predicate.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
同时,我需要使用QuerydslBinderCustomizer
所以我可以自定义过滤行为
public interface DepartmentRepository
extends CrudRepository<Department, UUID>,
PagingAndSortingRepository<Department, UUID>,
QuerydslPredicateExecutor<Department>,
QuerydslBinderCustomizer<QDepartment> {
@Override
default public void customize(QuerydslBindings bindings, QDepartment root) {
bindings.bind(root.version).first((path, value) -> path.goe(value));
bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value));
}
}
当我使用 @QueryInit
时,没有调用 customize
并且我的自定义不起作用
我已经尝试更新最后一个 Querydsl
版本 4.4.0 并添加 com.mysema.querydsl
querydsl-apt
但无论如何都不起作用
目前我在服务级别上使用谓词,像这样
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
所以我想我不能在customize()
里面配置EntityPath
,因为它是在调用存储库时调用的
适用于我的代码的解决方案:
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
---change---
QDepartment initalizedRoot = new QDepartment(QDepartment.department.getMetadata(),
PathInits.getFor(QDepartment.department.getMetadata(), new PathInits("*.*", "project.customer.company")));
---end change---
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
----2020 年 10 月 16 日更新----
我现在面临一种奇怪的行为。
经过多次测试后,我无需在我的服务上使用 PathInits
配置即可使一切正常运行,仅在我的实体中使用 @QueryInit
并在我的存储库中使用 customize()
...
我认为库更新负责纠正这种情况。
但是在编译和 运行 几次之后(改变除了这个配置之外的其他东西),customize()
已经不再被调用了。
调用 list()
方法而不触发 customize()
.
所以..我在我的服务中简单插入了 PathInit
配置代码,现在又调用了 customize()
。
代码是这样的,customize()
没有在存储库上调用
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
所以我改成了这个,现在 customize()
在存储库上被调用:
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
QDepartment qTest = new QDepartment(QDepartment.department.getMetadata(), PathInits.DIRECT2);
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
qTest
变量已初始化但未在任何地方使用,但它仍然影响行为。
看起来 new QDepartment(...)
是强制调用 customize()
的关键。
--- 另一个更新,更多信息 ---
以上代码仅在我处于调试模式时有效。
---最终解决方案---
要解决这个问题,我所要做的就是将绑定到我的控制器上的存储库 bindings = DepartmentRepository.class
。
public Page<Department> list(@QuerydslPredicate(root = Department.class, bindings = DepartmentRepository.class) Predicate predicate,
@PageableDefault Pageable pageable) {
return service.list(predicate, pageable);
}
可能spring-data
忽略了QueryDSL 静态元模型中声明的默认QueryInits。没有什么能阻止您将 EntityPath 表达式包装在另一个具有更多初始化路径的 EntityPath 表达式中:
default public void customize(QuerydslBindings bindings, QDepartment root) {
QDepartment initalizedRoot = new QDepartment(root)
// or
QDepartment initalizedRoot = new QDepartment(root.getMetadata(), PathInits.getFor(root.getMetadata(), new PathInits("*.*", "project.customer.company")));
// use initializedRoot.project.customer.company
}
在这里找到解决方案
https://github.com/Cepr0/sb-querydsl-sd-demo
要使自定义生效,您需要将控制器谓词绑定到存储库
bindings = DepartmentRepository.class
@GetMapping
@ResponseBody
public Page<Department> list(@QuerydslPredicate(root = Department.class, bindings = DepartmentRepository.class) Predicate predicate,
@PageableDefault Pageable pageable) {
return service.list(predicate, pageable);
}
提供以下内容类
public class Department {
...
@OneToOne
@JoinColumn(name = "idDepartment")
@QueryInit("customer.company")
private Project project;
...
}
public class Project {
...
@OneToOne
@JoinColumn(name = "idCustomer")
private Customer customer;
...
}
public class Customer {
...
@OneToOne
@JoinColumn(name = "idCompany")
private Company company;
...
}
我需要在 project
上使用 @QueryInit
才能访问第 4 级或更高级别,如下所示:
predicate.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
同时,我需要使用QuerydslBinderCustomizer
所以我可以自定义过滤行为
public interface DepartmentRepository
extends CrudRepository<Department, UUID>,
PagingAndSortingRepository<Department, UUID>,
QuerydslPredicateExecutor<Department>,
QuerydslBinderCustomizer<QDepartment> {
@Override
default public void customize(QuerydslBindings bindings, QDepartment root) {
bindings.bind(root.version).first((path, value) -> path.goe(value));
bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value));
}
}
当我使用 @QueryInit
时,没有调用 customize
并且我的自定义不起作用
我已经尝试更新最后一个 Querydsl
版本 4.4.0 并添加 com.mysema.querydsl
querydsl-apt
但无论如何都不起作用
目前我在服务级别上使用谓词,像这样
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
所以我想我不能在customize()
里面配置EntityPath
,因为它是在调用存储库时调用的
适用于我的代码的解决方案:
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
---change---
QDepartment initalizedRoot = new QDepartment(QDepartment.department.getMetadata(),
PathInits.getFor(QDepartment.department.getMetadata(), new PathInits("*.*", "project.customer.company")));
---end change---
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
----2020 年 10 月 16 日更新----
我现在面临一种奇怪的行为。
经过多次测试后,我无需在我的服务上使用 PathInits
配置即可使一切正常运行,仅在我的实体中使用 @QueryInit
并在我的存储库中使用 customize()
...
我认为库更新负责纠正这种情况。
但是在编译和 运行 几次之后(改变除了这个配置之外的其他东西),customize()
已经不再被调用了。
调用 list()
方法而不触发 customize()
.
所以..我在我的服务中简单插入了 PathInit
配置代码,现在又调用了 customize()
。
代码是这样的,customize()
没有在存储库上调用
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
所以我改成了这个,现在 customize()
在存储库上被调用:
public Page<Department> list(Predicate predicate, Pageable pageable){
BooleanBuilder predicateDepartment = new BooleanBuilder(predicate);
UUID idCompany =
springUserDetailsService.getUserSpring().getIdCompany();
QDepartment qTest = new QDepartment(QDepartment.department.getMetadata(), PathInits.DIRECT2);
predicateDepartment.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
return repository.findAll(predicateDepartment, pageable);
}
qTest
变量已初始化但未在任何地方使用,但它仍然影响行为。
看起来 new QDepartment(...)
是强制调用 customize()
的关键。
--- 另一个更新,更多信息 ---
以上代码仅在我处于调试模式时有效。
---最终解决方案---
要解决这个问题,我所要做的就是将绑定到我的控制器上的存储库 bindings = DepartmentRepository.class
。
public Page<Department> list(@QuerydslPredicate(root = Department.class, bindings = DepartmentRepository.class) Predicate predicate,
@PageableDefault Pageable pageable) {
return service.list(predicate, pageable);
}
可能spring-data
忽略了QueryDSL 静态元模型中声明的默认QueryInits。没有什么能阻止您将 EntityPath 表达式包装在另一个具有更多初始化路径的 EntityPath 表达式中:
default public void customize(QuerydslBindings bindings, QDepartment root) {
QDepartment initalizedRoot = new QDepartment(root)
// or
QDepartment initalizedRoot = new QDepartment(root.getMetadata(), PathInits.getFor(root.getMetadata(), new PathInits("*.*", "project.customer.company")));
// use initializedRoot.project.customer.company
}
在这里找到解决方案 https://github.com/Cepr0/sb-querydsl-sd-demo
要使自定义生效,您需要将控制器谓词绑定到存储库
bindings = DepartmentRepository.class
@GetMapping
@ResponseBody
public Page<Department> list(@QuerydslPredicate(root = Department.class, bindings = DepartmentRepository.class) Predicate predicate,
@PageableDefault Pageable pageable) {
return service.list(predicate, pageable);
}