问题 JPA Criteria API:LEFT JOIN用于可选关系


我第一次使用Criteria API。它是关于抽象通用构建器的查询:

public TypedQuery<T> newQuery( Manager<?,T> manager )
{
    CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

    Class<T> genericClass = ( Class<T> ) ( ( ParameterizedType ) manager.getClass().getGenericSuperclass() ).getActualTypeArguments()[1];

    CriteriaQuery<T> criteriaQuery = builder.createQuery( genericClass );
    Root<T> root = criteriaQuery.from( genericClass );

    ...
}

电话 criteriaQuery.from( genericClass ); 生成SQL INNER JOIN 对于默认情况下在实体上找到的所有关系。这是一个问题,因为每个关系都为空(DB NULL 或者不使用外键并且具有无效引用的DB)结果列表中将缺少这些实体,从而有效地产生错误的搜索结果。

可以在这里找到一个例子: JPA Criteria查询Path.get左连接是可能的

对于由此类/方法实例化的查询,我想要发生的是实体上的所有关系,这里 genericClass,被映射为 optional = true

@ManyToOne( FetchType.EAGER, optional = true )
@JoinColumn( name = "CLOSE_USER_ID", referencedColumnName = "USER_ID" )
private User              closer;

生成SQL LEFT (OUTER) JOIN 代替 INNER JOIN

是否有标准的JPQ方式来完成这项工作?如果是这样,怎么样?

PS:通常没有办法事先知道具体类型,所以我能够实现我需要的唯一方法是使用某种元模型并手动生成连接(我想避免)。


我们正在使用EclipseLink 2.3


7180
2017-09-03 13:44


起源



答案:


.from(class)不对所有关系使用INNER连接,它只查询类。

只有在使用join()或fetch()API时,才会查询关系,以使用JoinType.LEFT的外连接使用join()。

https://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join

如果你没有调用join(),我不确定为什么你会看到连接。一些JPA提供程序自动加入获取所有EAGER关系,这可能就是您所看到的。我总是这么奇怪,也许你的JPA提供商有一个配置不要这样做,或者你可以建立关系LAZY。


8
2017-09-03 13:52



IIRC的问题是我们使用了左连接语法来表示from子句,但是使用了标准连接的顺序bys,这似乎掩盖了之前的左连接。 - Kawu


答案:


.from(class)不对所有关系使用INNER连接,它只查询类。

只有在使用join()或fetch()API时,才会查询关系,以使用JoinType.LEFT的外连接使用join()。

https://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join

如果你没有调用join(),我不确定为什么你会看到连接。一些JPA提供程序自动加入获取所有EAGER关系,这可能就是您所看到的。我总是这么奇怪,也许你的JPA提供商有一个配置不要这样做,或者你可以建立关系LAZY。


8
2017-09-03 13:52



IIRC的问题是我们使用了左连接语法来表示from子句,但是使用了标准连接的顺序bys,这似乎掩盖了之前的左连接。 - Kawu


我遇到过同样的问题... 经过调查后得出的结论是,你必须在你的jpql中使用左连接来处理这个问题 看到: http://www.objectdb.com/java/jpa/query/jpql/path#Navigation_through_a_NULL_value_


2
2017-11-13 03:35