PostgreSQL的.NET驱动程序Npgsql中参数对象的一个Bug

最近将公司的项目从SqlServer移植到PostgreSQL数据库上来,在调用数据库的存储过程(自定义函数)的时候,发现一个奇怪的问题,老是报函数无法找到。

先看一个PgSQL存储过程:

CREATE OR REPLACE FUNCTION updateattention(dm citext)
  RETURNS void AS
$BODY$
DECLARE
  
BEGIN
  update ZB set gzd=COALESCE(gzd,0)+1 where ZB.dm=$1 ;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION updateattention(citext) OWNER TO postgres;

在PostgreSQL中,函数和存储过程没有区别,这里我们把没有返回值的函数叫做存储过程吧,也许表诉的不太准确,还望大虾指正。

上面定义一个存储过程updateattention,它有一个自定义类型 citext,用于将字符串中类型换成不区分大小写的类型,它的定义如下:

CREATE OR REPLACE FUNCTION citext(character)
  RETURNS citext AS
'rtrim1'
  LANGUAGE internal IMMUTABLE STRICT
  COST 1;
ALTER FUNCTION citext(character) OWNER TO postgres;

下面是调用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框架内置了日志对象和异常对象,它能够为你抛出详细的错误信息。

如果采用下面的方式调用,又没有问题:

db.ExecuteNonQuery("select * from updateattention(@dm)",                 System.Data.CommandType.Text, new System.Data.IDataParameter[] { para });

------------------------------------------------------------------------------------

尽管该方式可以作为一种替代方案,但要用select * from 这种方式调用存储过程,总觉得很别扭,还得找到问题的真正原因。

这个 "function ... does not exist" 的问题很难搜索,最终在国外找到一篇文章讨论类似的问题:

http://pgfoundry.org/forum/forum.php?thread_id=637&forum_id=519

文中有人说,可能是参数的类型转换问题,但我这里只是将参数进行了大小写转换,应该不会有类似Int32到Int64这类问题。

无赖,只有将调用存储过程的.NET程序代码一个一个排查,当注释掉

para.DbType = DbType.AnsiString;

的时候,程序居然能够正常运行通过了!

之前也曾经怀疑过是不是DbType的问题,但是当把鼠标放到VS2010的编辑器中para 对象下面的时候,智能提示显示 DbType="{String}".

默认情况下,参数对象的DbType属性值是

DbType.String

难道

DbType.AnsiString==DbType.String ??

看了一下定义,它们是有区别的,DbType.AnsiString表示非Unicode的变长字符串,DbType.String 表示Unicode的变长字符串。

一般情况下,ANSI编码表示当前系统编码,所以我猜想AnsiString在我的机器上是Gb2312编码的,查了一下数据库的编码,它是UTF-8格式的,难怪难怪,PostgreSQL给我提示找不到 updatefundattention(text) 函数,注意下,实际上这个函数的参数不是text类型的,它实际上应该是 character 类型,PostgreSQL可以定义同名的函数,但函数可以有不同的参数类型,有点像C#的方法重载。

到此,问题似乎解决了,但还没完:

VS2010的智能提示有Bug?

第一次有这个念头我都觉得不可思议,因为以前在VS2008的时候曾经调试过类似的代码,赶紧将上面的.net代码中的参数对象换成其它数据库类型的参数对象试试看:

//获取PostgreSQL的数据访问对象
PWMIS.DataProvider.Data.AdoHelper db = MyDB.GetDBHelperByConnectionName("PostgreSQL");
//使用 SqlServer 的参数对象
IDataParameter para = new SqlParameter(); 
para.ParameterName = "@dm";
para.DbType = DbType.AnsiString;
para.Value = "KF0355";
db.ExecuteNonQuery("updateattention",
                System.Data.CommandType.StoredProcedure,
                new System.Data.IDataParameter[] { para });

再此将光标放到para.DbType 上,这次提示正确了,是“{AnsiString}”;

将上面的代码放到VS2008中再次验证,智能提示正确,看来不是VS2010的Bug,呵呵。

故此,得到的结论:

PostgreSQL的.NET数据访问驱动程序的参数对象DbType属性存在一个设置成AnsiString之后查看该属性的结果却是String的Bug!

PS:虽然查看属性的确有这样一个Bug,但好像程序内部做了正确的处理,要不我的程序最终是无法运行通过的。

后记

PostgreSQL的.NET数据驱动程序的这个问题引起的问题使得我困扰了2天左右的时间,不得不发帖说明一下这个过程,现在国内有关PostgreSQL的资料太少,写点东西供大家参考一下。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

iOS逆向工程之Hopper中的ARM指令

虽然前段时间ARM被日本软银收购了,但是科技是无国界的,所以呢ARM相关知识该学的学。现在看ARM指令集还是倍感亲切的,毕竟大学里开了ARM这门课,并且做了不少...

34770
来自专栏大学生计算机视觉学习DeepLearning

c++ 网络编程(七)TCP/IP LINUX下 socket编程 基于套接字的标准I/O函数使用 与 fopen,feof,fgets,fputs函数用法

原文链接:https://www.cnblogs.com/DOMLX/p/9614820.html

23440
来自专栏xingoo, 一个梦想做发明家的程序员

【Spring开发】—— AOP之方法级拦截

前言: 前面介绍了Spring的核心模块以及相关的依赖注入等概念。这篇讲解一下spring的另一个重点,AOP面向切面编程。   说道AOP不得不提到几...

21480
来自专栏Python研发

Django之Model世界

django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)

13720
来自专栏QQ音乐技术团队的专栏

一种避免 iOS 内存碎片的方法

CFStringCreateWithBytes 方法分配的字符串是堆空间,如果数据过长,则很容易产生内存碎片。解决这个问题有两种思路:一是在栈空间分配内存,二是...

80700
来自专栏chenssy

这些Spring中的设计模式,你都知道吗?

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。

10310
来自专栏机器学习从入门到成神

java.lang.StackOverflowError异常解决

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

1.8K20
来自专栏進无尽的文章

简述OC语言

对于一门语言的学习是需要时间领悟的,而对于一些原理性的问题,我们需要清楚其核心思想,知其然而知其所以然,这样才能有利于自己的后续发展。本文只是简述,没有面面具到...

23920
来自专栏大内老A

.NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]

在《上篇》中我们谈到ResourceManager在默认的情况下只能提供对内嵌于程序集的.resources资源文件的存取。为了实现对独立二进制.resourc...

20260
来自专栏我叫刘半仙

原荐Spring AOP是什么?你都拿它做什么?

         对于最近博主最近写博客的兴致大发,我也在思考:为什么而写博客?在互联网时代,无论你是牛人大咖,还是小白菜鸟,都有发表自己看法的权利。无论你是对...

33540

扫码关注云+社区

领取腾讯云代金券