在 Hibernate 5.6 中将 String[] 作为 text[] 传递给 NamedNativeQuery

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

我有一个带有此签名的 Postgres 函数:

CREATE OR REPLACE FUNCTION public.ums_rate_permissions_for_collection(user_roles_arr text[], profile_id bigint, collection_id bigint)

我在 Hibernate 5.6 中通过 NamedNativeQuery 访问此函数,但在将 String[] 作为参数传递给此方法以用作 text[] 时遇到问题。

本机查询:

@NamedNativeQuery(
                name = "getUserRolesPermissionsForCollection",
                query = "SELECT * FROM ums_rate_permissions_for_collection(ARRAY[:profileList], :profileId, :collectionId)"
        )

DAO:

public UmsRolesNavigationPermissionVO getRolePermissionsForCollection(final List<String> userRoles, final Long profileId, final Long collectionId) {
        String[] param = userRoles.toArray(new String[0]);

        NativeQuery query = this.getSession()
                .getNamedNativeQuery("getUserRolesPermissionsForCollection")
                .setParameterList("profileList", param)
                .setParameter("profileId", profileId)
                .setParameter("collectionId", collectionId);

        List result = query.list();

当我在 postgres 控制台中运行此查询时,它工作正常:

SELECT * FROM ums_rate_permissions_for_collection(ARRAY['Sales User', 'Admin'], 141, 330)

而且,如果我的参数中只有一个元素,则一切正常。但是一旦数组中有 2 个或更多值,我就会收到这些错误:

Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
        at deployment.tg-clienta.war//org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:103)
        at deployment.tg-clienta.war//org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:37)
        at deployment.tg-clienta.war//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
        at deployment.tg-clienta.war//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
        at deployment.tg-clienta.war//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:67)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.getResultSet(Loader.java:2322)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2075)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2037)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.doQuery(Loader.java:956)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.doList(Loader.java:2868)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.doList(Loader.java:2850)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682)
        at deployment.tg-clienta.war//org.hibernate.loader.Loader.list(Loader.java:2677)
        at deployment.tg-clienta.war//org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)
        at deployment.tg-clienta.war//org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2186)
        at deployment.tg-clienta.war//org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1204)
        at deployment.tg-clienta.war//org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:177)
        at deployment.tg-clienta.war//org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1617)
        ... 27 more
Caused by: org.postgresql.util.PSQLException: ERROR: function ums_rate_permissions_for_collection(record[], bigint, bigint) does not exist
  Hinweis: No function matches the given name and argument types. You might need to add explicit type casts.
  Position: 15
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553)
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2285)
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:323)
        at [email protected]//org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481)
        at [email protected]//org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401)
        at [email protected]//org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164)
        at [email protected]//org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
        at [email protected]//org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:504)
        at deployment.tg-clienta.war//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
        ... 41 more

看起来 Hibernate 正在将其转换为某种记录数组而不是文本数组。我尝试了几件事,例如,将所有单独的字符串包装在 '' 内或将我的值转换为 postgres 文本数组表示形式:

private String convertToPostgresArray(List<String> userRoles) {
        StringBuilder sb = new StringBuilder();
        sb.append("'{");
        for (int i = 0; i < userRoles.size(); i++) {
            if (i > 0) {
                sb.append(",");
            }
            sb.append(userRoles.get(i));
        }
        sb.append("}'");
        return sb.toString();
    }

后一种方法似乎至少将真实的 text[] 传递给 Postgres,如错误堆栈所示:

Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "AND"
  Wobei: PL/pgSQL function ums_rate_permissions_for_collection(text[],bigint,bigint) line 73 at RETURN QUERY
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553)
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2285)
        at [email protected]//org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:323)
        at [email protected]//org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481)
        at [email protected]//org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401)
        at [email protected]//org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164)
        at [email protected]//org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
        at [email protected]//org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:504)
        at deployment.tg-clienta.war//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
        ... 39 more

但没有什么真正有帮助。有什么想法吗?

java hibernate jpa
1个回答
0
投票

我的同事给了我解决这个问题的秘诀。解决方案是使用自定义类型并使用

.setParameter(String name, Object value, Type type)
方法添加它。

String[] param = userRoles.toArray(new String[0]);

NativeQuery query = this.getSession()
                .getNamedNativeQuery("getUserRolesPermissionsForCollection")
                .setParameter("profileList", param, new CustomType(new CustomStringArrayType()))
                .setParameter("profileId", profileId)
                .setParameter("collectionId", collectionId);

这个

CustomStringArrayType
看起来像这样:

    public class CustomStringArrayType implements UserType {
        @Override
        public String[] nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
                    throws HibernateException, SQLException {
                if (names != null && names.length > 0 && rs != null && rs.getArray(names[0]) != null) {
                    return (String[]) rs.getArray(names[0]).getArray();
                }
                return null;
            }
    }
© www.soinside.com 2019 - 2024. All rights reserved.