PostgreSQL的.NET驅(qū)動(dòng)程序Npgsql中參數(shù)對(duì)象的一個(gè)Bug
最近將公司的項(xiàng)目從SqlServer移植到PostgreSQL數(shù)據(jù)庫上來,在調(diào)用數(shù)據(jù)庫的存儲(chǔ)過程(自定義函數(shù))的時(shí)候,發(fā)現(xiàn)一個(gè)奇怪的問題,老是報(bào)函數(shù)無法找到。
先看一個(gè)PgSQL存儲(chǔ)過程:
- 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中,函數(shù)和存儲(chǔ)過程沒有區(qū)別,這里我們把沒有返回值的函數(shù)叫做存儲(chǔ)過程吧,也許表訴的不太準(zhǔn)確,還望大蝦指正。
上面定義一個(gè)存儲(chǔ)過程updateattention,它有一個(gè)自定義類型 citext,用于將字符串中類型換成不區(qū)分大小寫的類型,它的定義如下:
- CREATE OR REPLACE FUNCTION citext(character)
- RETURNS citext AS
- 'rtrim1'
- LANGUAGE internal IMMUTABLE STRICT
- COST 1;
- ALTER FUNCTION citext(character) OWNER TO postgres;
下面是調(diào)用updateattention存儲(chǔ)過程的代碼:
- //獲取PostgreSQL的數(shù)據(jù)訪問對(duì)象
- PWMIS.DataProvider.Data.AdoHelper db = MyDB.GetDBHelperByConnectionName("PostgreSQL");
- //獲取PostgreSQL的參數(shù)對(duì)象
- 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數(shù)據(jù)開發(fā)框架)的數(shù)據(jù)訪問對(duì)象AdoHelper來進(jìn)行相關(guān)的數(shù)據(jù)訪問操作,它采用反射工廠模式,根據(jù)系統(tǒng)的配置實(shí)例化具體的數(shù)據(jù)訪問類,這里使用的是PostgreSQL數(shù)據(jù)訪問類。
運(yùn)行該程序,出現(xiàn)下面的錯(cuò)誤:
PDF.NET AdoHelper 查詢錯(cuò)誤:
- DataBase ErrorMessage:ERROR: 42883: function updatefundattention(text) does not exist
- SQL:updatefundattention
- CommandType:StoredProcedure
- Parameters:
- Parameter["@jjdm"] = "KF0355" //DbType=String
PDF.NET框架內(nèi)置了日志對(duì)象和異常對(duì)象,它能夠?yàn)槟銙伋鲈敿?xì)的錯(cuò)誤信息。
如果采用下面的方式調(diào)用,又沒有問題:
- db.ExecuteNonQuery("select * from updateattention(@dm)",
- System.Data.CommandType.Text,
- new System.Data.IDataParameter[] { para });
------------------------------------------------------------------------------------
盡管該方式可以作為一種替代方案,但要用select * from 這種方式調(diào)用存儲(chǔ)過程,總覺得很別扭,還得找到問題的真正原因。
這個(gè) "function ... does not exist" 的問題很難搜索,最終在國外找到一篇文章討論類似的問題:
http://pgfoundry.org/forum/forum.php?thread_id=637&forum_id=519
文中有人說,可能是參數(shù)的類型轉(zhuǎn)換問題,但我這里只是將參數(shù)進(jìn)行了大小寫轉(zhuǎn)換,應(yīng)該不會(huì)有類似Int32到Int64這類問題。
無賴,只有將調(diào)用存儲(chǔ)過程的.NET程序代碼一個(gè)一個(gè)排查,當(dāng)注釋掉
para.DbType = DbType.AnsiString;
的時(shí)候,程序居然能夠正常運(yùn)行通過了!
之前也曾經(jīng)懷疑過是不是DbType的問題,但是當(dāng)把鼠標(biāo)放到VS2010的編輯器中para 對(duì)象下面的時(shí)候,智能提示顯示 DbType="{String}".
默認(rèn)情況下,參數(shù)對(duì)象的DbType屬性值是
DbType.String
難道
DbType.AnsiString==DbType.String ??
看了一下定義,它們是有區(qū)別的,DbType.AnsiString表示非Unicode的變長字符串,DbType.String 表示Unicode的變長字符串。
一般情況下,ANSI編碼表示當(dāng)前系統(tǒng)編碼,所以我猜想AnsiString在我的機(jī)器上是Gb2312編碼的,查了一下數(shù)據(jù)庫的編碼,它是UTF-8格式的,難怪難怪,PostgreSQL給我提示找不到 updatefundattention(text) 函數(shù),注意下,實(shí)際上這個(gè)函數(shù)的參數(shù)不是text類型的,它實(shí)際上應(yīng)該是 character 類型,PostgreSQL可以定義同名的函數(shù),但函數(shù)可以有不同的參數(shù)類型,有點(diǎn)像C#的方法重載。
到此,問題似乎解決了,但還沒完:
VS2010的智能提示有Bug?
***次有這個(gè)念頭我都覺得不可思議,因?yàn)橐郧霸赩S2008的時(shí)候曾經(jīng)調(diào)試過類似的代碼,趕緊將上面的.net代碼中的參數(shù)對(duì)象換成其它數(shù)據(jù)庫類型的參數(shù)對(duì)象試試看:
- //獲取PostgreSQL的數(shù)據(jù)訪問對(duì)象
- PWMIS.DataProvider.Data.AdoHelper db = MyDB.GetDBHelperByConnectionName("PostgreSQL");
- //使用 SqlServer 的參數(shù)對(duì)象
- 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 });
再此將光標(biāo)放到para.DbType 上,這次提示正確了,是“{AnsiString}”;
將上面的代碼放到VS2008中再次驗(yàn)證,智能提示正確,看來不是VS2010的Bug,呵呵。
故此,得到的結(jié)論:
PostgreSQL的.NET數(shù)據(jù)訪問驅(qū)動(dòng)程序的參數(shù)對(duì)象DbType屬性存在一個(gè)設(shè)置成AnsiString之后查看該屬性的結(jié)果卻是String的Bug!
PS:雖然查看屬性的確有這樣一個(gè)Bug,但好像程序內(nèi)部做了正確的處理,要不我的程序最終是無法運(yùn)行通過的。
后記
PostgreSQL的.NET數(shù)據(jù)驅(qū)動(dòng)程序的這個(gè)問題引起的問題使得我困擾了2天左右的時(shí)間,不得不發(fā)帖說明一下這個(gè)過程,現(xiàn)在國內(nèi)有關(guān)PostgreSQL的資料太少,寫點(diǎn)東西供大家參考一下。
原文鏈接:http://www.cnblogs.com/bluedoctor/archive/2011/05/18/2050276.html
【編者推薦】
- 思科推新數(shù)據(jù)中心解決方案支持SQL Server
- 數(shù)據(jù)庫日常維護(hù)常用的腳本部分收錄
- SQL Server表最小行的一個(gè)糾結(jié)問題
- 云端數(shù)據(jù)庫:微軟SQL Azure及其應(yīng)用場景
- SQL點(diǎn)滴之收集SQL Server線程等待信息