【问题标题】:hibernate with ltree native named query使用 ltree 本机命名查询休眠
【发布时间】:2018-12-26 15:00:20
【问题描述】:

我正在尝试运行包含 ltree 函数和运算符的 PostgreSQL 本机查询。

定义如下:

@NamedNativeQuery(
            name = "pathSegmentQuery",
            query = "select ltree2text(okm_path) as okm_path, " +
                    "       index(okm_path, text2ltree(:lastSegment)) + 2 <> nlevel(okm_path) as haschild, " +
                    "       case " +
                    "         when index(okm_path, text2ltree(:lastSegment)) + 1 <> nlevel(okm_path) " +
                    "                 then ltree2text(subpath(okm_path, index(okm_path, text2ltree(:lastSegment)) + 1, 1)) " +
                    "           end as child " +
                    "from document " +
                    "where okm_path ~ :pathLike " +
                    "and " +
                    "index(okm_path, text2ltree(:path)) + 1 <> nlevel(okm_path) ",
            resultSetMapping = "pathSegmentQueryRSMapping")

调用如下:

public List<PathSegment> getPathChildren(String path, String lastSegment) {
    Query query = entityManager.createNamedQuery("pathSegmentQuery");
    String pathLike = "'*." + path + ".*'";

    query.setParameter("path", path);
    query.setParameter("pathLike", pathLike);
    query.setParameter("lastSegment", lastSegment);

    return query.getResultList();
}

结果是错误ERROR: operator does not exist: ltree ~ character varying

当我尝试直接针对数据库运行查询时,它运行正常:

select ltree2text(okm_path) as okm_path,
   index(okm_path, text2ltree('_root_')) + 2 <> nlevel(okm_path) as haschild,
   case
     when index(okm_path, text2ltree('_root_')) + 1 <> nlevel(okm_path)
             then ltree2text(subpath(okm_path, index(okm_path, text2ltree('_root_')) + 1, 1))
       end as child
from document
where
    okm_path ~ '*._root_.*'
and
    index(okm_path, text2ltree('_root_')) + 1 <> nlevel(okm_path)

从错误中可以看出 hibernate(?) 不喜欢 ~ 运算符右侧的类型,但是正如您所见,我在后面的查询中使用了该字符串并且工作正常。

那么我需要对休眠查询做什么才能成功运行查询?

编辑: 当我将okm_path ~ :pathLike 替换为"where okm_path ~ '*._root_.*' " 时,我会得到:

org.postgresql.util.PSQLException: ERROR: syntax error at position 0 错误

休眠:5.2.9.Final

postgresql:9.2.23

【问题讨论】:

    标签: java postgresql hibernate ltree


    【解决方案1】:

    原来有lquery()函数在你对lquery进行操作时需要调用。

    所以我的查询转换为

    ...
    where okm_path ~ lquery(:pathLike)
    ...
    

    这样就解决了问题

    【讨论】:

      【解决方案2】:

      错误

      operator does not exist: ltree ~ character varying
      

      应该读作

      operator does not exist: <left_data_type> <operator> <right_data_type> varying
      

      这意味着没有为这些数据类型定义运算符。例如,当运算符的左侧是整数而右侧是 varchar 时,就会发生这种情况,此时错误为 ERROR: operator does not exist: integer = character varying

      这里的问题是当你设置右侧的值时,

      query.setParameter("pathLike", pathLike) 
      

      pathLike 是一个字符串。所以 Postgres 认为这是将 ltree 与字符串进行比较。当您直接执行 SQL 时,右侧被视为 ltree 表达式而不是字符串。

      我不确定这是否可行,但你可以试试 ltree 可以直接转换为 varchar,但你可以试试这个吗?:

      query.setParameter("pathLike", pathLike, Hibernate.OBJECT)
      

      另见Java type in JDBC to Postgres ltree

      【讨论】:

      • 当我将左侧 ltree 转换为 ltree2text(okm_path) ~ '*._root_.*' 时,它给出了 [2201B] ERROR: invalid regular expression: quantifier operand invalid。我需要右侧的lquery。但是没有像text2lquery 这样的功能,所以hibernate无法理解它以某种方式给postgre提供了错误的信息
      • @greengold 我明白了。我认为问题是,当您从休眠中传递*._root_.* 时,它作为字符串传递(因为pathLikequery.setParameter("pathLike", pathLike) 中的字符串),而当您直接执行查询(或硬编码值)时,将采用参数作为 ltree 表达式而不是字符串。我对 ltree 不太熟悉,所以我不确定是否有办法明确设置 ltree 表达式。
      • @greengold 你可以试试query.setParameter("pathLike", pathLike, Hibernate.OBJECT) 吗?另见stackoverflow.com/questions/21447077/…
      • 首先,Query 仅接受 TemporalType 作为第三个参数。在您链接的线程中,第三个参数被设置为准备好的语句。然后,TemporalType 只定义了日期、时间、时间戳枚举,所以没有真正符合我的情况。我已经编辑了我的问题并添加了当我省略查询的:pathLike 参数并直接硬编码一些值时会发生什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多