有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

同时使用QuerydslBinderCustomizer和@QueryInit时出现java问题

给下面的课程

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{},但无论如何都不起作用


目前我在服务级别上使用谓词,如下所示

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()

我认为lib更新负责纠正这种情况。 但是在编译和运行了几次之后(除了这个配置之外,还更改了其他内容),就不再调用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);
}

共 (2) 个答案

  1. # 1 楼答案

    可能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
    }
    
    
  2. # 2 楼答案

    找到解决办法了吗 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);
    }