Query DSL中能否将子类Q类型实例赋值给父类Q类型参数使用
问题原因
- Q类继承关系不匹配
QueryDSL自动生成的Q类默认不会跟随业务实体的继承关系继承:哪怕Child1、Child2实体类继承自Parent,生成的QChild1、QChild2也属于独立类型,不会继承QParent,因此直接把QChild1实例传入要求QParent类型的Filter构造方法,会报类型不匹配错误。 - 方法逻辑存在语法错误
你写的getPredicates方法存在两处逻辑错误:
- 三目运算符
name == null ? null : query.name.eq(name)的结果没有赋值给变量,属于无效语句 - 最后
query.isNotNull().and(name)中,name是字符串类型,不能直接和布尔表达式做逻辑运算,运行时也会报错
解决方法
方法1:调用侧手动包装子类Q类为父类Q类型
QueryDSL生成的父类Q类提供了create静态方法,可以把子类的查询路径包装为父类Q类型,直接适配原有Filter逻辑:
// 调用侧做类型转换即可,Filter类不需要修改 childOneRepo.findAll(new Filter(QParent.create(QChild1.child1.getMetadata())).getPredicates("test name"));
同时修复getPredicates方法的语法问题:
BooleanExpression getPredicates(String name) { BooleanExpression predicate = query.isNotNull(); if (name != null) { predicate = predicate.and(query.name.eq(name)); } return predicate; }
方法2:重构Filter为泛型实现,兼容所有子类Q类型
如果不想每次调用都手动转换,可以把Filter调整为泛型结构,内部自动做类型包装:
class Filter<T extends Parent> { private final QParent query; // 入参接收任意继承Parent的实体的查询路径,内部统一包装为QParent public Filter(EntityPath<T> entityPath) { this.query = QParent.create(entityPath.getMetadata()); } BooleanExpression getPredicates(String name) { BooleanExpression predicate = query.isNotNull(); if (name != null) { predicate = predicate.and(query.name.eq(name)); } return predicate; } }
修改后原有调用代码不需要额外调整即可直接运行。
方法3:修改QueryDSL配置,让子类Q类自动继承父类Q类
在父类实体上添加@QuerySupertype注解,标记为查询超类,QueryDSL生成子类Q类时就会自动继承QParent:
@QuerySupertype @MappedSuperclass // JPA场景需要额外加这个注解 public class Parent { private String name; // 其他公共属性 }
配置完成后重新生成Q类,原有Filter和调用代码都不需要修改即可正常运行。
内容的提问来源于stack exchange,提问作者java dev
相关产品推荐
相关产品推荐

