.net访问postgresql数据库发生“找不到函数名”的问题追踪 -凯发k8官方网
postgresql是一个使用广泛的免费开源的数据库,与mysql比较,它更适合复杂的企业计算任务,而mysql在互联网领域应用更为广泛,究其原因,可能是postgresql拥有支持最多的数据类型,甚至包括数组类型,ip地址类型等,可以使用c,sql,pl/pgsql,phython等多种方式编写强大的自定义函数,因此特别适合处理复杂的计算问题。如果想要将sqlserver数据库迁移到其它类型的数据库,postgresql是比较好的选择。
尽管postgresql使用比较广泛,但在国内相关资料太少,我们在数据库迁移的过程中,遇到了不少问题,比如我的上一篇文章postgresql的.net驱动程序npgsql中参数对象的一个bug 中关于“找不到函数名”的问题,解决起来比较“辣手”,可以使用“追踪”来形容了。本篇继续对这个问题进行深入探究。
1,问题回顾:
在上一篇文章中说到,有一个postgresql函数 updateattention ,它有一个自定义的函数参数,下面是函数头:
create or replace function updateattention(dm citext)
returns void as
$body$
--函数体略
参数dm 的类型是citex,一个自定义的数据类型,使用它来作为函数参数或者变量的类型,在进行数据查询的时候可以不区分大小写,它的定义是:
create or replace function citext(character)
returns citext as
'rtrim1'
language internal immutable strict
cost 1;
alter function citext(character) owner to postgres;
下面是调用使用c#调用updateattention存储过程的代码:
//获取postgresql的数据访问对象
pwmis.dataprovider.data.adohelper db = mydb.getdbhelperbyconnectionname("postgresql");
//获取postgresql的参数对象
idataparameter para = db.getparameter();
para.parametername = "@dm";
para.dbtype = dbtype.ansistring;
para.value = "kf0355";
db.executenonquery("updateattention",
system.data.commandtype.storedprocedure,
new system.data.idataparameter[] { para });
程序使用pdf.net(pwmis数据开发框架)的数据访问对象adohelper来进行相关的数据访问操作,它采用反射工厂模式,根据系统的配置实例化具体的数据访问类,这里使用的是postgresql数据访问类。
运行该程序,出现下面的错误:
pdf.net adohelper 查询错误:database errormessage:error: 42883: function updatefundattention(text) does not exist
sql:updatefundattention
commandtype:storedprocedure
parameters:
parameter["@jjdm"] = "kf0355" //dbtype=string
pdf.net框架内置了日志对象和异常对象,它能够为你抛出详细的错误信息,参看“pdf.net的sql日志 ”
2,问题聚焦
一开始还以为是函数名大小写的问题,仔细核对后发现没有问题,然后尝试对代码进行仔细排查。
将上面的程序中第6行代码
para.dbtype = dbtype.ansistring;
注释掉,程序运行通过,怀疑参数类型不能够设置成ansistring,设置成下面的方式:
para.dbtype = dbtype.string;
今天再次将目光聚集在错误信息的函数参数上:
updatefundattention(text)
难道postgresql的数据类型text 对应的.net程序类型既不是string,也不是ansistring?
又搜索了下,在http://npgsql.projects.postgresql.org/docs/manual/usermanual.html 找到了一张数据类型对照表:
supported data types
npgsql supports the following data types:
postgresql type | npgsqldbtype | system.dbtype enum | .net system type |
int8 | bigint | int64 | int64 |
bool | boolean | boolean | boolean |
box, circle, line, lseg, path, point, polygon | box, circle, line, lseg, path, point, polygon | object | object |
bytea | bytea | binary | byte[] |
date | date | date | datetime, npgsqldate |
float8 | double | double | double |
int4 | integer | int32 | int32 |
money | money | decimal | decimal |
numeric | numeric | decimal | decimal |
float4 | real | single | single |
int2 | smallint | int16 | int16 |
text | text | string | string |
time | time | time | datetime, npgsqltime |
timetz | time | time | datetime, npgsqltimetz |
timestamp | timestamp | datetime | datetime, npgsqltimestamp |
timestamptz | timestamptz | datetime | datetime, npgsqltimestamptz |
interval | interval | object | timespan, npgsqlinterval |
varchar | varchar | string | string |
inet | inet | object | npgsqlinet, ipaddress (there is an implicity cast operator to convert npgsqlinet objects into ipaddress if you need to use ipaddress and have only npgsqlinet) |
bit | bit | boolean | boolean, int32 (if you use an int32 value, odd values will be translated to bit 1 and even values to bit 0) |
uuid | uuid | guid | guid |
array | array | object | array in order to explicitly use array type, specify npgsqldbtype as an 'or'ed type: npgsqldbtype.array | npgsqldbtype.integer for an array of int32 for example. |
可以看到 数据库的text 类型是可以对应.net程序的string类型的,看来问题的关键的确是函数参数类型问题。
为了验证这个想法,将函数的参数类型改为varchar类型:
create or replace function updateattention(dm varchar)
returns void as
$body$
--函数体略
再次运行前面说的.net数据访问程序,运行通过!
故此得到结论:
postgresql数据库的函数中使用“自定义数据类型”,在.net程序可能无法设置正确的dbtype,从而出现找不到函数名的错误!
3,“灵异现象”分析
前面说,将
para.dbtype = dbtype.ansistring;
代码注释即可,也就是不对npgsqlparameter.dbtype 设置任何值,那么dbtype的缺省值是什么呢?
在vs2010的“即时窗口”打印了一下未设置值的para.dbtype,发现它的值是:
string
由于上一篇文章已经验证npgsql的参数对象dbtype无论怎么设置,获取该属性值的时候都是string,所以还是无法得知它的默认属性值是什么。
于是一个很偶然的念头出现:
npgsqlparameter对象的默认值是不是object类型?
另外我们的函数使用了自定义的citext类型,所以很可能需要使用dbtype.object类型。
重新修改代码成下面的方式:
//获取postgresql的数据访问对象
pwmis.dataprovider.data.adohelper db = mydb.getdbhelperbyconnectionname("postgresql");
//获取postgresql的参数对象
idataparameter para = db.getparameter();
para.parametername = "@dm";
para.dbtype = dbtype.object;
para.value = "kf0355";
db.executenonquery("updateattention",
system.data.commandtype.storedprocedure,
new system.data.idataparameter[] { para });
运行程序,正常通过,看来问题找到了,就是它,在postgresql的自定义类型函数参数中,.net程序的存储过程调用参数应该设置成 dbtype.object!
转载于:https://www.cnblogs.com/bluedoctor/archive/2011/05/19/2051271.html
总结
以上是凯发k8官方网为你收集整理的.net访问postgresql数据库发生“找不到函数名”的问题追踪的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 推荐10个很棒的 css3 开发工具
- 下一篇: