条件 API 未生成左外连接

Criteria API is not generating left outer join

我有 3 个实体,实际上为了简洁起见,还有更多实体连接在一起,我跳过了这些,我使用的是 open jpa 2.2.2 和 oracle 11g。任何想法这里出了什么问题?

Entity SystemRules{
@OneToMany(mappedBy = "systemRule", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<ServiceActionMap> serviceActionMap;
}

Entity ServiceActionMap{
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "SYSTEM_RULE_ID")
    private SystemRules systemRule;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "RFS_TYPE_ID", nullable = true)
    private RfsTypeMap rfsType;
}

Entity RfsTypeMap{
    @Id
    @Column(name="RFS_TYPE_ID" ,nullable=false)
    private BigDecimal rfsTypeId;

    @Column(name="RFS_NAME")
    private String rfsName;
}

现在,我正在尝试按 RfsTypeMap.rfsName 对结果进行排序,我正在按照以下方式使用条件生成器创建查询

CriteriaQuery<SystemRules> query = cb.createQuery(SystemRules.class);
Root<SystemRules> root= query.from(SystemRules.class);
root.fetch(SystemRules_.serviceActionMap).fetch(ServiceActionMap_.rfsType, JoinType.LEFT);

我的order by 子句是这样的

cb.desc(cb.upper(systemRules.get("serviceActionMap").get("rfsType").get("rfsName").as(String.class)));

生成 JPQL 看起来像,我希望在 ServiceActionMap 和 RfsTypeMap 之间有一个左外连接子句,但它丢失了。同样被翻译成SQL,我想念那些将ServiceActionMap.rfsType作为空值的记录。

SELECT  DISTINCT s FROM SystemRules s INNER JOIN FETCH s.serviceActionMap  INNER JOIN FETCH s.serviceActionMap  INNER JOIN FETCH s.ruleProperty  INNER JOIN FETCH s.ruleProperty where ... ORDER BY UPPER(s.serviceActionMap.rfsType.rfsName)

我尝试过这里的几个答案但没有成功,尝试明确地将 ServiceActionMap.rfsType 的 where 子句设置为 null,正如少数答案所建议的那样,但它被忽略了,因为 join 发生在 where 评估之前。这个问题 openJPA outer join on optional many-to-one when have order by clause 在某个地方与我的场景相匹配,但无法通过条件 API 生成建议的 JPQL。

我在 apache jira https://issues.apache.org/jira/browse/OPENJPA-2318 上发现了一个相关的错误。但是,不确定是不是这样。

我看到每个连接都重复两次,甚至连接别名也总是引用 SystemRules。可能是orderby导致了重复的inner join,我们可能需要明确的使用Join对象来引用extended column。

CriteriaQuery<SystemRules> query = cb.createQuery(SystemRules.class);
Root<SystemRules> root = query.from(SystemRules.class);
Join<SystemRules, ServiceActionMap> join1 = root.join(SystemRules_.serviceActionMap, JoinType.INNER);
Join<ServiceActionMap, RfsTypeMap> join2 = join1.join(ServiceActionMap_.rfsType, JoinType.LEFT);
query.orderBy(cb.desc(cb.upper(join2.get(RfsTypeMap_.rfsName))));