.net訪問PostgreSQL資料庫發生“找不到函數名”的問題追蹤

來源:互聯網
上載者:User
文章目錄
  • Supported data types
  •  

    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的Data Access Objects
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資料開發架構)的Data Access ObjectsAdoHelper來進行相關的資料訪問操作,它採用反射原廠模式,根據系統的配置執行個體化具體的資料訪問類,這裡使用的是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;

程式依然運行不通過,拋出上面同樣的錯誤,只有將這行代碼注釋掉才可以允許通過,思索很久仍然沒有結果,於是昨天寫了本文開頭說的那篇文章(PostgreSQL的.NET驅動程式Npgsql中參數對象的一個Bug)。

 

今天再次將目光聚集在錯誤資訊的函數參數上:

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的Data Access Objects
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!

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.