英文:
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
来能够访问第四层或更多层次,像这样:
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();
---变更---
QDepartment initalizedRoot = new QDepartment(QDepartment.department.getMetadata(),
PathInits.getFor(QDepartment.department.getMetadata(), new PathInits("*.*", "project.customer.company")));
---结束变更---
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);
}
英文:
Giving the following classes
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;
...
}
I need to use @QueryInit
on project
to be able to access the 4th level or more, like this:
predicate.and(
QDepartment.department.project.customer.company.id.eq(idCompany)
);
At the same time, I need to use QuerydslBinderCustomizer
so I can customize the filter behavior
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));
}
}
When I use the @QueryInit
, the customize
is not called and my customization doesn't work
I've already tried to update the the last Querydsl
version 4.4.0 and add the com.mysema.querydsl
querydsl-apt
but does not work anyway
Currently I'm using the predicate on service level, like this
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);
}
So I think I can't configure the EntityPath
inside the customize()
, because it's called when the repository is called
The solution applyed to my code:
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);
}
----Update 10/16/2020----
I'm facing a weird behavior now.
After many tests I was able to make everything works right without using the PathInits
configuration on my service, only using the @QueryInit
in my Entity and the customize()
in my Repository...
I thought the lib update was responsible to correct the situation.
But after compiling and running a couple of times (changing other things but this config), the customize()
has not been called anymore.
The list()
method is called without trigger the customize()
.
So.. I made a simple insert of the PathInit
config code in my service and now the customize()
has been called again.
The code was this, and the customize()
is not called on repository
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);
}
So I changed to this, and now the customize()
is called on repository:
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);
}
The qTest
variable is initialized but is not used anywhere, but its affecting the behavior even so.
It looks like the new QDepartment(...)
is the key to force the customize()
to be called.
--- Another update, more info ---
The code above works only if I'm on debug mode.
--- Final solution ---
All I had to do to solve this problem is to put the binding to the Repository bindings = DepartmentRepository.class
on my Controller.
public Page<Department> list(@QuerydslPredicate(root = Department.class, bindings = DepartmentRepository.class) Predicate predicate,
@PageableDefault Pageable pageable) {
return service.list(predicate, pageable);
}
答案1
得分: 1
可能 spring-data
忽略了在 QueryDSL 静态元模型中声明的默认 QueryInits。没有任何阻止您将 EntityPath 表达式包装在另一个具有更多初始化路径的 EntityPath 表达式中:
default public void customize(QuerydslBindings bindings, QDepartment root) {
QDepartment initalizedRoot = new QDepartment(root)
// 或者
QDepartment initalizedRoot = new QDepartment(root.getMetadata(), PathInits.getFor(root.getMetadata(), new PathInits("*.project.customer.company")));
// 使用 initializedRoot.project.customer.company
}
英文:
Probably spring-data
ignores the default QueryInits declared in the QueryDSL static metamodel. Nothing prevents you from wrapping an EntityPath expression in another EntityPath expression with more initialized paths:
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
}
答案2
得分: 0
在这里找到了解决方案
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);
}
英文:
Got the solution here
https://github.com/Cepr0/sb-querydsl-sd-demo
To have the customize to work you need to bind the controller Predicate to the Repository
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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论