簡體   English   中英

ODP.NET,托管讀取 LONG 列結果為 ORA-01009

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM