.net访问PostgreSQL数据库发生“找不到函数名”的问题追踪
??? 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
總結
以上是生活随笔為你收集整理的.net访问PostgreSQL数据库发生“找不到函数名”的问题追踪的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐10个很棒的 CSS3 开发工具
- 下一篇: linux cmake编译源码,linu