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

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:

最近将公司的项目从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的资料太少,写点东西供大家参考一下。

 



    本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/archive/2011/05/18/2050276.html,如需转载请自行联系原作者



相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
4月前
|
开发框架 JavaScript .NET
ASP.NET Core的超级大BUG
ASP.NET Core的超级大BUG
44 0
|
5月前
|
程序员 数据库
VB.NET—Bug调试(参数话查询、附近语法错误)
VB.NET—Bug调试(参数话查询、附近语法错误)
26 0
|
安全 中间件 API
这难道不是.NET5的bug? 在线求锤?
hello,最近在对一个使用.NET5项目的认证授权系统进行重构,对.NET 5的授权中间件的源码有些看法。也希望同学们能帮我理解。
这难道不是.NET5的bug? 在线求锤?
|
SQL 算法 数据库
【开源】QuickPager ASP.NET2.0分页控件V2.0.0.6 修改了几个小bug,使用演示。
     由于项目里面还在使用vs2003,还没有使用新的分页控件,所以对新的分页控件的测试还很不到位,遗留了不少的bug,感谢网友试用提出宝贵意见。由于项目正在收尾中,时间也不是太充裕,所以使用说明也不够详细。
897 0
|
前端开发 开发工具 IDE
|
Web App开发 前端开发 .NET