.net訪(fǎng)問(wèn)PostgreSQL數(shù)據(jù)庫(kù)發(fā)生“找不到函數(shù)名”的問(wèn)題追蹤
PostgreSQL是一個(gè)使用廣泛的免費(fèi)開(kāi)源的數(shù)據(jù)庫(kù),與MySQL比較,它更適合復(fù)雜的企業(yè)計(jì)算任務(wù),而MySQL在互聯(lián)網(wǎng)領(lǐng)域應(yīng)用更為廣泛,究其原因,可能是PostgreSQL擁有支持最多的數(shù)據(jù)類(lèi)型,甚至包括數(shù)組類(lèi)型,IP地址類(lèi)型等,可以使用C,SQL,PL/Pgsql,Phython等多種方式編寫(xiě)強(qiáng)大的自定義函數(shù),因此特別適合處理復(fù)雜的計(jì)算問(wèn)題。如果想要將SqlServer數(shù)據(jù)庫(kù)遷移到其它類(lèi)型的數(shù)據(jù)庫(kù),PostgreSQL是比較好的選擇。
盡管PostgreSQL使用比較廣泛,但在國(guó)內(nèi)相關(guān)資料太少,我們?cè)跀?shù)據(jù)庫(kù)遷移的過(guò)程中,遇到了不少問(wèn)題,比如我的上一篇文章PostgreSQL的.NET驅(qū)動(dòng)程序Npgsql中參數(shù)對(duì)象的一個(gè)Bug 中關(guān)于“找不到函數(shù)名”的問(wèn)題,解決起來(lái)比較“辣手”,可以使用“追蹤”來(lái)形容了。本篇繼續(xù)對(duì)這個(gè)問(wèn)題進(jìn)行深入探究。
1,問(wèn)題回顧:
在上一篇文章中說(shuō)到,有一個(gè)PostgreSQL函數(shù) updateattention ,它有一個(gè)自定義的函數(shù)參數(shù),下面是函數(shù)頭:
- CREATE OR REPLACE FUNCTION updateattention(dm citext)
- RETURNS void AS
- $BODY$
- --函數(shù)體略
參數(shù)dm 的類(lèi)型是citex,一個(gè)自定義的數(shù)據(jù)類(lèi)型,使用它來(lái)作為函數(shù)參數(shù)或者變量的類(lèi)型,在進(jìn)行數(shù)據(jù)查詢(xún)的時(shí)候可以不區(qū)分大小寫(xiě),它的定義是:
- 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)用使用C#調(diào)用updateattention存儲(chǔ)過(guò)程的代碼:
- //獲取PostgreSQL的數(shù)據(jù)訪(fǎng)問(wèn)對(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ù)開(kāi)發(fā)框架)的數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象AdoHelper來(lái)進(jìn)行相關(guān)的數(shù)據(jù)訪(fǎng)問(wèn)操作,它采用反射工廠(chǎng)模式,根據(jù)系統(tǒng)的配置實(shí)例化具體的數(shù)據(jù)訪(fǎng)問(wèn)類(lèi),這里使用的是PostgreSQL數(shù)據(jù)訪(fǎng)問(wèn)類(lèi)。
運(yùn)行該程序,出現(xiàn)下面的錯(cuò)誤:
- PDF.NET AdoHelper 查詢(xún)錯(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ò)誤信息。
2,問(wèn)題聚焦
一開(kāi)始還以為是函數(shù)名大小寫(xiě)的問(wèn)題,仔細(xì)核對(duì)后發(fā)現(xiàn)沒(méi)有問(wèn)題,然后嘗試對(duì)代碼進(jìn)行仔細(xì)排查。
將上面的程序中第6行代碼
- para.DbType = DbType.AnsiString;
注釋掉,程序運(yùn)行通過(guò),懷疑參數(shù)類(lèi)型不能夠設(shè)置成AnsiString,設(shè)置成下面的方式:
- para.DbType = DbType.String;
程序依然運(yùn)行不通過(guò),拋出上面同樣的錯(cuò)誤,只有將這行代碼注釋掉才可以允許通過(guò),思索很久仍然沒(méi)有結(jié)果,于是昨天寫(xiě)了本文開(kāi)頭說(shuō)的那篇文章(PostgreSQL的.NET驅(qū)動(dòng)程序Npgsql中參數(shù)對(duì)象的一個(gè)Bug)。
今天再次將目光聚集在錯(cuò)誤信息的函數(shù)參數(shù)上:
updatefundattention(text)
難道PostgreSQL的數(shù)據(jù)類(lèi)型text 對(duì)應(yīng)的.NET程序類(lèi)型既不是String,也不是AnsiString?
又搜索了下,在http://npgsql.projects.postgresql.org/docs/manual/UserManual.html 找到了一張數(shù)據(jù)類(lèi)型對(duì)照表:
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. |
可以看到 數(shù)據(jù)庫(kù)的text 類(lèi)型是可以對(duì)應(yīng).net程序的String類(lèi)型的,看來(lái)問(wèn)題的關(guān)鍵的確是函數(shù)參數(shù)類(lèi)型問(wèn)題。
為了驗(yàn)證這個(gè)想法,將函數(shù)的參數(shù)類(lèi)型改為Varchar類(lèi)型:
- CREATE OR REPLACE FUNCTION updateattention(dm varchar)
- RETURNS void AS
- $BODY$
- --函數(shù)體略
再次運(yùn)行前面說(shuō)的.net數(shù)據(jù)訪(fǎng)問(wèn)程序,運(yùn)行通過(guò)!
故此得到結(jié)論:
PostgreSQL數(shù)據(jù)庫(kù)的函數(shù)中使用“自定義數(shù)據(jù)類(lèi)型”,在.NET程序可能無(wú)法設(shè)置正確的DbType,從而出現(xiàn)找不到函數(shù)名的錯(cuò)誤!
3,“靈異現(xiàn)象”分析
前面說(shuō),將
para.DbType = DbType.AnsiString;
代碼注釋即可,也就是不對(duì)NpgsqlParameter.DbType 設(shè)置任何值,那么DbType的缺省值是什么呢?
在VS2010的“即時(shí)窗口”打印了一下未設(shè)置值的para.DbType,發(fā)現(xiàn)它的值是:
String
由于上一篇文章已經(jīng)驗(yàn)證Npgsql的參數(shù)對(duì)象DbType無(wú)論怎么設(shè)置,獲取該屬性值的時(shí)候都是String,所以還是無(wú)法得知它的默認(rèn)屬性值是什么。
于是一個(gè)很偶然的念頭出現(xiàn):
NpgsqlParameter對(duì)象的默認(rèn)值是不是Object類(lèi)型?
另外我們的函數(shù)使用了自定義的citext類(lèi)型,所以很可能需要使用DbType.Object類(lèi)型。
重新修改代碼成下面的方式:
- //獲取PostgreSQL的數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象
- PWMIS.DataProvider.Data.AdoHelper db = MyDB.GetDBHelperByConnectionName("PostgreSQL");
- //獲取PostgreSQL的參數(shù)對(duì)象
- 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 });
運(yùn)行程序,正常通過(guò),看來(lái)問(wèn)題找到了,就是它,在PostgreSQL的自定義類(lèi)型函數(shù)參數(shù)中,.net程序的存儲(chǔ)過(guò)程調(diào)用參數(shù)應(yīng)該設(shè)置成 DbType.Object!
原文鏈接:http://www.cnblogs.com/bluedoctor/archive/2011/05/19/2051271.html
【編者推薦】
- 通用權(quán)限管理設(shè)計(jì)之?dāng)?shù)據(jù)庫(kù)結(jié)構(gòu)設(shè)計(jì)
- PostgreSQL的.NET驅(qū)動(dòng)程序Npgsql中參數(shù)對(duì)象的一個(gè)Bug
- SQL Server表最小行的一個(gè)糾結(jié)問(wèn)題
- 云端數(shù)據(jù)庫(kù):微軟SQL Azure及其應(yīng)用場(chǎng)景
- SQL點(diǎn)滴之收集SQL Server線(xiàn)程等待信息




















