使用 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" />
【讨论】:
其实正确的是<query-param name="id" type="long" />
。但我的函数也返回 ID,但事实并非如此。我在代码中设置了函数参数。
我认为这是问题所在。能不能只引入id输入参数作为新参数?以上是关于使用 PostgreSQL 和 NHibernate 的命名查询的主要内容,如果未能解决你的问题,请参考以下文章
prometheus使用postgresql-adapter连接postgresql
在 PostgreSQL 和 Slick 中使用自动递增字段
使用 PostgreSQL 和 NHibernate 的命名查询