【问题标题】:JPQL query - hibernate: with-clause not allowed on fetched associationsJPQL 查询 - 休眠:在获取的关联上不允许使用 with 子句
【发布时间】:2018-05-12 14:58:30
【问题描述】:

我有这样的 JPA 存储库和 JPQL 查询:

@Query("SELECT c from Campaign c" +
        " left join fetch c.postsList p on p.status = :postStatus" +
        " left join fetch p.platform" +
        " left join fetch c.campaignStatistics stat on stat.updateDate = :updateDate" +
        " where c.id =:id")
Campaign findCampaignWithPosts(
        @Param("id") Long id,
        @Param("postStatus") PostStatus postStatus,
        @Param("updateDate") LocalDate updateDate);

但它不起作用。我明白了:

org.hibernate.hql.internal.ast.QuerySyntaxException: with-clause not allowed on fetched associations; use filters

我去研究有关 JPA 2.1 规范的信息,这就是我发现的:

用于连接的连接条件来自映射的连接 列。这意味着 JPQL 用户通常不必 知道每个关系是如何连接的。在某些情况下,这是可取的 将附加条件附加到连接条件,通常在 外连接的情况。这可以通过 ON 子句来完成。开启 子句在 JPA 2.1 规范中定义,并且可以支持 一些 JPA 提供程序。 EclipseLink : Hibernate : TopLink - 支持 ON 子句。

需要注意的是,这种类型的查询对我没有任何帮助,因为在这个查询中有时我会得到 null,where 子句在连接表之后使用。

   @Query("SELECT c from Campaign c" +
            " left join fetch c.postsList p" +
            " left join fetch p.platform" +
            " left join fetch c.campaignStatistics stat" +
            " where c.id =:id" +
            " and p.status = :postStatus" +
            " and stat.updateDate = :updateDate")

在这种情况下该怎么办?除了如何使用本机查询之外,没有其他解决方案吗?但随后几乎所有 JPQL 查询的意义都丢失了。 我使用休眠版本 5.2.12

【问题讨论】:

  • 您是否检查过您的课程中的某些字段是否称为with
  • @Luiggi Mendoza 不,类中的所有字段都不包含'with'
  • 可能是说在使用FETCH JOIN的时候不能放ON子句?但这也是 JPA 规范所说的,所以你真的很惊讶吗? ON 仅允许在普通 JOIN 上使用
  • 另外,您声称引用了 JPA 规范,但我不知道您从哪里得到该文本;它不是来自 JPA 规范。 github.com/javaee/jpa-spec/blob/master/jsr338-MR/…
  • @DN1 我在 wikibooks link 上获得了此信息。可能没有正确表达,调用规范。但是在这种情况下怎么办?使用原生查询?

标签: java hibernate jpa join jpql


【解决方案1】:

你是对的,当你添加和 p.status = :postStatus 时,它会过滤掉连接右侧不存在的结果(即当活动没有帖子时)。

对我有用的是添加一个 OR 子句来接受连接右侧为 NULL 的情况。

因此,您应该将and p.status = :postStatus 替换为and (p IS NULL OR p.status = :postStatus)

所以这个请求应该有效:

@Query("SELECT c from Campaign c" +
            " left join fetch c.postsList p" +
            " left join fetch p.platform" +
            " left join fetch c.campaignStatistics stat" +
            " where c.id =:id" +
            " and (p is NULL OR p.status = :postStatus)" +
            " and stat.updateDate = :updateDate")

至于您收到的错误消息,我认为您不应该添加 ON 子句,因为它已经由 JPA/Hibernate 处理。

我使用的是 Hibernate 5.0.12。

【讨论】:

  • 这是not a good idea 使用WHERE 条件fetch 别名。
  • 这不是一个正确的答案。使用 where 子句不会提供与加入较小集合相同的结果。请参阅 Victor 的帖子,这是该问题的正确答案。
  • 只有当我想获得活动时,这个答案才正确,即使任何 postLists 没有 :postStatus?然后我想获得一个带有空 postList 的广告系列。对于这种情况,这个答案是不正确的。 @victor 提到了这一点。但没有提供解决方案。
【解决方案2】:

没有替代解决方案,因为当您有这样的谓词时:

and (p is NULL OR p.status = :postStatus)

然后出现3个案例:

  1. getPostsList() 返回空列表
  2. getPostsList() 返回包含至少一个具有查询状态的元素的列表
  3. getPostsList() 返回不包含查询状态的元素的列表

在第 3 种情况下,您将完全丢失 Campaign 的所有行。但是获取具有 1 个状态的那些

因为当postList的列表不为空时,left join不会加入nulls

【讨论】:

    【解决方案3】:

    这是not a good idea 在获取别名时使用 WHERE 条件

    试试这个

    @Query("SELECT c from Campaign c" +
            " left join c.postsList p" +
            " left join fetch c.postsList " +
            " left join fetch p.platform " +
            " left join c.campaignStatistics stat" +
            " left join fetch c.campaignStatistics " +
            " where c.id =:id" +
            " and (p is NULL OR p.status = :postStatus)" +
            " and stat.updateDate = :updateDate")
    

    【讨论】:

    • 为什么是负面的?
    猜你喜欢
    • 2015-12-22
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2017-06-22
    相关资源
    最近更新 更多