[英]ODP.NET, Managed reading LONG column results in ORA-01009
我正在嘗試在我的 .net 應用程序中獲取視圖的來源。 為此,我查詢DBA_VIEWS
:它有一個列TEXT
其中包含我需要的內容。 類型是LONG
。
如果我使用非托管驅動程序執行此操作,則一切都會按預期進行。 與托管驅動程序相同的代碼導致ORA-01009: missing mandatory parameter
。 在命令周圍添加事務並使用斷點和“慢”步驟有時會導致相同的代碼工作。
ODP.NET 版本為 19,Oracle DB 為 18c 快捷版。 奇怪的是,無論驅動程序類型如何,相同的代碼在 Oracle Database 12c 上都可以正常工作。
我可能需要更改數據庫或代碼中的某些設置嗎? 我完全迷失在這里。
我用於測試的代碼:
Imports System.Data.Common
Imports Oracle.ManagedDataAccess
'Imports Oracle.DataAccess
Module Views
Function CreateCommand(Connection As DbConnection) As System.Data.Common.DbCommand
Dim cmd As Data.Common.DbCommand = Connection.CreateCommand()
With CType(cmd, Client.OracleCommand)
.BindByName = True
.FetchSize = &H100000 '1 Mb
.InitialLONGFetchSize = -1 'the entire LONG or LONG RAW data is prefetched and stored in the fetch array.
.InitialLOBFetchSize = -1 'the entire LOB data is prefetched and stored in the fetch array.
End With
Return cmd
End Function
Sub query()
Try
Using DBConnection = New Client.OracleConnection("User ID=TESTUSER;Password=TESTPWD;Data Source=TESTDB;Pooling=True")
DBConnection.Open()
Using DBConnection.BeginTransaction()
Using cmdSQL = CType(CreateCommand(DBConnection), Client.OracleCommand)
cmdSQL.CommandText = "select TEXT from DBA_VIEWS where VIEW_NAME = :0"
Dim p = cmdSQL.CreateParameter()
p.ParameterName = "0"
p.Value = "TEST_VIEW"
cmdSQL.Parameters.Add(p)
Dim sw = Stopwatch.StartNew
Using rdr = cmdSQL.ExecuteReader
rdr.FetchSize = 2 ^ 20
While rdr.Read
Dim row(rdr.FieldCount - 1) As Object
rdr.GetProviderSpecificValues(row)
Dim x = row(0)
Console.WriteLine($"{x.ToString.Length} bytes")
End While
End Using
Console.WriteLine($"{sw.ElapsedMilliseconds} ms")
End Using
End Using
End Using
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
End Module
遺憾的是,Oracle 已棄用LONG
數據類型多年,但內部數據仍多次使用 LONG 數據。
您可以編寫一個函數,然后通過調用該函數來獲取數據:
create or replace function GetViewText(v in varchar2) return clob is
ret CLOB;
BEGIN
FOR aRow IN (SELECT TEXT FROM DBA_VIEWS WHERE VIEW_NAME = v) LOOP
ret := aRow.TEXT;
-- or ret := TO_CLOB(aRow.TEXT);
END LOOP;
RETURN ret;
END;
您可以使用帶有輸出參數的匿名塊和對ExecuteNonQuery
的調用。 您的命令文本將是
"begin select TEXT into :0 from DBA_VIEWS where VIEW_NAME = :1; end;"
添加2個參數。 確保
' Parameter #1 has
p.Direction = ParameterDirection.Output
p.OracleDbType = OracleDbType.Long
p.Size = 1000000
並使用命令cmd.ExecuteNonQuery()
。 然后,當檢索到參數時,只需使用其值
Dim txt As String = cmd.Parametersp[0].Value.ToString()
這個答案的另一種方法是(ab)使用dbms_xmlgen.getxml
。 我們可以使用它來查詢單個視圖的代碼(如我原來的問題)
with input as (
select
:0 as VIEW_NAME
from dual
)
SELECT
substr(
text_xml,
instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'),
instr(text_xml, '</LONGCOL>', -1) - (instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'))
) as TEXT
from
(
-- getxml can return malformed xml (which is good in this case)
-- while getxmltype can not.
select dbms_xmlgen.getxml(q'{
SELECT TEXT as LONGCOL
FROM SYS.DBA_VIEWS
WHERE VIEW_NAME = '}' || input.VIEW_NAME || q'{'
}') as text_xml
from input
)
或創建我們自己的DBA_VIEWS
版本。
create or replace view APP_SCHEMA.DBA_VIEWS
as
select
OWNER, VIEW_NAME, TEXT_LENGTH,
case
when (TEXT_VC is not null and TEXT_LENGTH <= 4000)
then to_clob(TEXT_VC)
when TEXT is NULL
then NULL
else (
SELECT
substr(
text_xml,
instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'),
--instr(text_xml, '</LONGCOL>', -1) - (instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'))
TEXT_LENGTH
) as TEXT
from
(
-- getxml can return malformed xml (which is good in this case)
-- while getxmltype can not.
select dbms_xmlgen.getxml(q'{
SELECT TEXT as LONGCOL
FROM SYS.DBA_VIEWS
WHERE OWNER = '}' || OWNER || q'{'
and VIEW_NAME = '}' || VIEW_NAME || q'{'
}') as text_xml
from dual
)
)
end as TEXT,
TEXT_VC, TYPE_TEXT_LENGTH, TYPE_TEXT, OID_TEXT_LENGTH, OID_TEXT, VIEW_TYPE_OWNER, VIEW_TYPE, SUPERVIEW_NAME, EDITIONING_VIEW, READ_ONLY, CONTAINER_DATA, BEQUEATH, ORIGIN_CON_ID, DEFAULT_COLLATION, CONTAINERS_DEFAULT, CONTAINER_MAP, EXTENDED_DATA_LINK, EXTENDED_DATA_LINK_MAP, HAS_SENSITIVE_COLUMN
from sys.dba_views
;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.