Spring MongoDB项目中多Mongo Repository集成QueryDSL遇实体继承查询异常的解决方案问询
首先,咱们直接定位你遇到的错误根源:PropertyReferenceException: No property customize found for type Sub1Profile!——这是因为你的Sub1ProfileRepository里的customize方法签名和QuerydslBinderCustomizer<QSub1Profile>要求的不匹配,导致Spring Data无法识别这个方法是用来定制QueryDSL绑定的。
1. 修正Sub1ProfileRepository的方法签名
你原来的customize方法参数用了QProfile root,但你的Repository实现的是QuerydslBinderCustomizer<QSub1Profile>,所以参数必须是QSub1Profile,而且要加上@Override注解明确重写接口方法。修正后的代码如下:
@Repository public interface Sub1ProfileRepository extends MongoRepository<Sub1Profile, ObjectId>, QuerydslPredicateExecutor<Sub1Profile>, QuerydslBinderCustomizer<QSub1Profile> { @Override default void customize(QuerydslBindings bindings, QSub1Profile root) { // 这里可以复用父类的绑定逻辑,或者添加子类特有的绑定规则 bindings.bind(String.class) .first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase); } }
2. 确保QueryDSL正确生成所有Q类
要确认你的构建工具(Maven/Gradle)配置了QueryDSL的APT注解处理器,能为所有继承层级的实体(Profile、Sub1Profile以及后续的孙类)生成对应的Q类(QProfile、QSub1Profile等)。
比如Maven的核心配置示例:
<build> <plugins> <plugin> <groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/java</outputDirectory> <processor>com.querydsl.mongodb.morphia.MorphiaAnnotationProcessor</processor> </configuration> </execution> </executions> </plugin> </plugins> </build>
3. 自动过滤子类文档(利用MongoDB的_class字段)
因为你把所有Profile存在同一个集合,Spring Data MongoDB会自动通过_class字段过滤对应类型的文档——只要你的Repository泛型是Sub1Profile,默认查询就只会返回Sub1Profile及其子类的文档,不需要额外写过滤条件。如果需要手动强化类型过滤,也可以在Repository里定义默认方法:
default Iterable<Sub1Profile> findAll() { QSub1Profile sub1Profile = QSub1Profile.sub1Profile; return findAll(sub1Profile._class.eq(Sub1Profile.class.getName()) .or(sub1Profile._class.like(Sub1Profile.class.getName() + "$%"))); // 匹配所有孙类 }
4. 优化:提取通用绑定逻辑到基类
为了避免每个Repository重复写相同的绑定代码,你可以创建一个通用的QueryDSL绑定基类,让所有Profile相关的Repository继承:
public interface BaseProfileRepository<T extends Profile> extends MongoRepository<T, ObjectId>, QuerydslPredicateExecutor<T>, QuerydslBinderCustomizer<QProfile> { @Override default void customize(QuerydslBindings bindings, QProfile root) { bindings.bind(String.class) .first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase); } }
然后你的子Repository可以这样继承并扩展:
@Repository public interface Sub1ProfileRepository extends BaseProfileRepository<Sub1Profile>, QuerydslBinderCustomizer<QSub1Profile> { @Override default void customize(QuerydslBindings bindings, QSub1Profile root) { // 先调用父类的通用绑定逻辑 BaseProfileRepository.super.customize(bindings, root); // 添加子类特有的绑定规则 bindings.bind(root.sub1String).first(StringExpression::containsIgnoreCase); } }
这样既复用了通用逻辑,又能灵活扩展子类的定制化绑定。
内容的提问来源于stack exchange,提问作者mirrom

