使用 PostgreSQL 和 NHibernate 的命名查询

Posted

技术标签:

【中文标题】使用 PostgreSQL 和 NHibernate 的命名查询【英文标题】:Named queries with PostgreSQL and NHibernate 【发布时间】:2015-01-28 20:38:21 【问题描述】:

我正在与 NHibernate 命名查询和 PostgreSQL 搏斗,但无法让它工作。我在 PostgreSQL 数据库中有一个函数:

create or replace function x(results refcursor, id_ bigint)
  returns refcursor
  as
  $$
begin
  open results for
select
    id,
    name,
    number
from
    table_name
where
    id = id_;

    return results;
end;
  $$ language plpgsql;

然后我在 NHibernate 中做了一个映射:

<sql-query name="SqlQueryForTesting">
    <return-scalar column="id" type="long" />
    <return-scalar column="name" type="string" />
    <return-scalar column="number" type="string" />
    <![CDATA[
      begin;
      select x('table_name_cursor', :id);
      fetch all in table_name_cursor;
      commit;
    ]]>
  </sql-query>

最后制作了一个调用这个命名查询的方法。

public IList MethodForNamedQuery(int id)
        
            var query = Session.GetNamedQuery("SqlQueryForTesting");
            query.SetInt32("id", id);
            return query.List();
        

问题是这段代码给了我一个错误。

System.IndexOutOfRangeException
Field not found
   at Npgsql.NpgsqlRowDescription.FieldIndex(String fieldName)
   at NHibernate.Driver.NHybridDataReader.GetOrdinal(String name)
   at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name)
   at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name, ISessionImplementor session, Object owner)
   at NHibernate.Loader.Custom.CustomLoader.ScalarResultColumnProcessor.Extract(Object[] data, IDataReader resultSet, ISessionImplementor session)
   at NHibernate.Loader.Custom.CustomLoader.ResultRowProcessor.BuildResultRow(Object[] data, IDataReader resultSet, Boolean hasTransformer, ISessionImplementor session)
   at NHibernate.Loader.Custom.CustomLoader.GetResultColumnOrRow(Object[] row, IResultTransformer resultTransformer, IDataReader rs, ISessionImplementor session)
   at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)

NHibernate.Exceptions.GenericADOException
could not execute query
[ begin;
      select x('table_name_cursor', :p0);
      fetch all in table_name_cursor;
      commit; ]
  Name:id - Value:2

如果我通过 pgAdmin 运行查询,它可以完美运行并返回一行。所以我猜问题出在映射的某个地方。谁能说我的映射有什么问题?

【问题讨论】:

为什么要加begin/commit 我也试过没有开始和提交。错误还是一样。 你能解决这个问题吗? 【参考方案1】:

NHibernate 不知道它是本机查询,因此它试图将其解释为常规 NHibernate 查询,该查询将按映射实体进行搜索。

如果您可以将函数创建为存储过程,则可以定义命名查询,例如 this example:

<sql-query name="selectAllEmployments_SP">
    <return alias="emp" class="Employment">
        <return-property name="employee" column="EMPLOYEE"/>
        <return-property name="employer" column="EMPLOYER"/>
        <return-property name="startDate" column="STARTDATE"/>
        <return-property name="endDate" column="ENDDATE"/>
        <return-property name="regionCode" column="REGIONCODE"/>
        <return-property name="id" column="EID"/>
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
    </return>
    exec selectAllEmployments
</sql-query>

【讨论】:

PostgreSQL 没有存储过程 @evilone 我明白了。但是像存储过程一样调用函数并不难,对吧? 根据sqlines.com/postgresql/how-to/…我需要从游标中获取结果,没有其他方法是可能的。【参考方案2】:

我猜id 应该是一个输入参数,但在您的查询中它被声明为使用return-scalar 的输出参数。尝试将其更改为query-param 以查看它是否有效:

<query-param column="id" type="long" />

【讨论】:

其实正确的是&lt;query-param name="id" type="long" /&gt;。但我的函数也返回 ID,但事实并非如此。我在代码中设置了函数参数。 我认为这是问题所在。能不能只引入id输入参数作为新参数?

以上是关于使用 PostgreSQL 和 NHibernate 的命名查询的主要内容,如果未能解决你的问题,请参考以下文章

prometheus使用postgresql-adapter连接postgresql

在 PostgreSQL 和 Slick 中使用自动递增字段

使用 PostgreSQL 和 NHibernate 的命名查询

如何使用 Java 和 PostgreSQL 执行 \d tablename [重复]

PostgreSQL索引分类及使用

如何使用 JPA 和 Hibernate 映射 PostgreSQL 枚举