如何强制Querydsl为带@Transient的@ManyToOne对象生成路径
首先得说清楚:你用@Transient标记objectB字段的做法本身就会让Querydsl忽略这个字段——因为@Transient的作用就是告诉ORM(包括JPA和Querydsl)这个字段不属于持久化模型的一部分,所以Q类里缺失objectB路径是完全符合预期的行为。你的核心需求是禁止JPA在操作ObjectA时同步ObjectB,但要保留这个关联用于Querydsl查询,所以不能用@Transient来实现,得换个思路。
下面是两种可行的解决方案:
方案1:用JPA级联配置替代@Transient(推荐)
去掉@Transient注解,通过@ManyToOne的cascade属性来控制级联行为,明确告诉JPA不要对ObjectB执行同步操作。这样既保留了JPA的关联映射,Querydsl也会正常生成Q类里的objectB路径。
修改后的ObjectA代码:
public class ObjectA { // 空的cascade集合表示不启用任何级联操作 @ManyToOne(cascade = {}) private ObjectB objectB; }
或者你也可以更明确地指定允许的级联类型(比如只允许刷新,不允许增删改):
@ManyToOne(cascade = CascadeType.REFRESH) private ObjectB objectB;
这样配置后,JPA在更新/删除ObjectA时,完全不会影响ObjectB,同时Querydsl的QObjectA里会正常生成objectB路径,你的查询代码repo.findAll(QObjectA.objectA.objectB.isNull(), pageable)就能正常运行了。
方案2:用Querydsl的@QueryType强制生成路径(特殊场景)
如果你因为某些特殊原因,必须保留@Transient注解(比如这个字段确实不需要JPA持久化,但你需要用它来构建Querydsl查询),可以添加Querydsl的@QueryType注解,指定这个字段是实体类型,让Querydsl强制生成对应的路径。
修改后的ObjectA代码:
import com.querydsl.core.annotations.QueryType; import com.querydsl.core.types.PropertyType; public class ObjectA { @ManyToOne @Transient @QueryType(PropertyType.ENTITY) private ObjectB objectB; }
注意:这种方式下,JPA依然会忽略这个字段(因为@Transient还在),所以你无法依赖JPA自动加载这个关联,查询时可能需要手动写JOIN语句来关联ObjectA和ObjectB。但至少Querydsl会生成Q类里的objectB属性,解决你当前的报错问题。
为什么@QueryProperty/@QueryInit没用?
因为@Transient已经让Querydsl跳过了对这个字段的解析流程,这些注解只有在Querydsl识别到字段是持久化模型的一部分时才会生效,所以先解决字段被Querydsl识别的问题才是关键。
内容的提问来源于stack exchange,提问作者sparkhee93

