本机递归 HQL 查询上的 Hibernate-ORM 6 NonUniqueDiscoveredSqlAliasException

问题描述 投票:0回答:1

我正在将 Spring Boot 应用程序 (spring-boot-starter-parent) 从 2.6.1 升级到 3.4.1。 该升级的一部分与 hibernate 5 到 6 的升级有关,特别是 hibernate core 6.6.4.Final 与 postgresql 的升级。在这种情况下,在一个测试用例中会出现以下异常,从而阻止升级。

...
org.hibernate.loader.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [id_number] during auto-discovery of a native-sql query
    at org.hibernate.query.results.ResultSetMappingImpl.resolve(ResultSetMappingImpl.java:289)
    at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.resolveJdbcValuesSource(JdbcSelectExecutorStandardImpl.java:340)
    at 
...

此异常与此本机 HQL 查询相关,即以下查询:

...
@Override
public List<ParentNodeChieldTreeDTOInterface> findAllSubNodesRecursively(NodeInterface node) {
    try {
        Session session = getSessionFactory().openSession();
        session.beginTransaction();

        String sql_query = 
                        " WITH RECURSIVE tree AS "
                      + "("
                      + " SELECT id, id_number, node_type_id, cast (array[] as BIGINT[]) AS ancestors"
                      + " FROM node" 
                                 
                      + " UNION ALL"
                                 
                      + " SELECT node.id, node.id_number, node.node_type_id, tree.ancestors || node.parent_id_number"
                      + " FROM node, tree"
                      + " WHERE node.parent_id_number = tree.id_number"
                      + ") "
                      + "SELECT DISTINCT ON (id_number) tree.id_number, * FROM tree WHERE (:Argument1 = ANY(tree.ancestors) )"
                      + "  ORDER BY tree.id_number" 
                      ;
        
        @SuppressWarnings("unchecked")
        Query<Object[]> query = session.createNativeQuery(sql_query)
                .addScalar("id", byte[].class)
                .addScalar("id_number", Long.class)
                .addScalar("node_type_id", Integer.class)
                .addScalar("ancestors",  LongArrayType.INSTANCE)
                ;
        
        Long nodeIdHex = node.getIdNumber();
        query.setParameter("Argument1", nodeIdHex, Long.class);
        
        List<Object[]> objectCollection = (List<Object[]>) query.list();
        
        List<ParentNodeChieldTreeDTOInterface> parentNodeChieldTreeDTOList = new ArrayList<ParentNodeChieldTreeDTOInterface>();
        if (objectCollection.iterator().hasNext()) {
            for (Object[] objects : objectCollection) {
                byte[] nodeUUIDArray = (byte[]) objects[0];
                long nodeIdNumber = (long) objects[1];
                int nodeTypeIdNumber = (int) objects[2];
                Object parentNodes =  objects[3];
                long[] parents =  (long[]) parentNodes;
                
                ParentNodeChieldTreeDTOInterface dtoObject = new ParentNodeChieldTreeDTO(
                        nodeUUIDArray, 
                        nodeIdNumber, 
                        nodeTypeIdNumber, 
                        parents
                        );
                
                if(logger.isDebugEnabled()) {
                    ByteBuffer buffer = ByteBuffer.wrap(nodeUUIDArray);
                    UUID nodeUUID = ByteBufferOperations.byteBufferToUUID(buffer);
                    
                    logger.debug("Cheild Node UUID       : " + nodeUUID.toString() );
                    logger.debug("Parent Nodes           : " + parents);
                    logger.debug("Cheild Node            : " + nodeUUIDArray);
                }
                parentNodeChieldTreeDTOList.add(dtoObject);
            }
        }
        session.getTransaction().commit();
        session.close();
        return parentNodeChieldTreeDTOList;
    } catch (Exception e) {
        logger.error("Exception", e);
        throw e;
    }
}
...

我必须提到,完全相同的本机 SQL 查询代码在 spring-boot-starter-parent 2.6.1 即 hibernate 5 中没有抛出异常。

现在异常表明sql别名[id_number]是重复的,从逻辑角度来看确实是这样,因为这里我们正在执行递归操作或者正确地说是对同一个表进行迭代操作。即,实际上以下列“node.id_number”和“id_number”基本上是 select 语句中的同一列,它们基本上是同一件事。但这就是递归查询的重点。 即,这是表的各个部分在 postgres 中的样子

...
# \d node;
                                             Table "public.node"
      Column      |           Type           | Collation | Nullable |                 Default                 
------------------+--------------------------+-----------+----------+-----------------------------------------
...
 node_type_id     | integer                  |           | not null | 
 id_number        | bigint                   |           | not null | nextval('node_id_number_seq'::regclass)
 parent_id_number | bigint                   |           |          | 
 id               | bytea                    |           | not null | 
 parent_id        | bytea                    |           |          | 
... 

那么在 Hibernate 6 中如何处理此类问题。即虽然“node.id_number”和“id_number”是同一个表/事物,但我的理解是在这种情况下别名确实不同。如何在 Hibernate 6 中实现此功能。 经过一段时间的搜索后,我在 SO 上发现了一个类似的问题,但那个问题不涉及同一张表上的递归。

有用的资源:

https://vladmihalcea.com/hibernate-with-recursive-query/

分层树中的递归搜索

PostgreSQL 中分层数据的递归查询

spring-boot hibernate recursion hibernate-mapping
1个回答
0
投票

我能够通过更改来解决问题 “在(id_number)树上选择不同的id_number” 到 选择不同的(tree.id_number) 然后在 DBeaver 中我只看到 4 列而不是 5 列,即不再有重复的 id_number。但在这被认为是最终答案之前,还需要进一步测试。我并不是一个真正的 SQL 人员,因此如果有人可以推荐“SELECT DISTINCT ON (tree.id_number)”解决方法,我将非常感激。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.