【问题标题】:ODP.NET, Managed reading LONG column results in ORA-01009ODP.NET,托管读取 LONG 列导致 ORA-01009
【发布时间】:2021-06-30 22:59:57
【问题描述】:

我正在尝试在我的 .net 应用程序中获取视图的来源。 为此,我查询DBA_VIEWS:它有一列TEXT 正是我需要的。类型为LONG

如果我使用非托管驱动程序,一切都会按预期工作。 与托管驱动程序相同的代码导致ORA-01009: missing mandatory parameter。 使用断点“慢”步骤有时围绕命令添加事务会导致相同的代码工作。

ODP.NET 版本是 19,Oracle DB 是 18c Express Edition。奇怪的是,无论驱动程序类型如何,相同的代码都可以在 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

【问题讨论】:

  • 不确定它会起作用,但试试这个:"begin select TEXT into :0 from DBA_VIEWS where VIEW_NAME = :1; end;"。添加2个参数。确保第一个parameterDirection = outputoracleDbType = Longsize=1000000。并使用cmd.ExecuteNonQuery。然后,如果检索到参数,只需使用cmd.Parametersp[0].Value.ToString()
  • @T.S.这确实有效,谢谢!
  • 添加了答案。自己知道也很好。

标签: oracle vb.net odp.net odp.net-managed


【解决方案1】:

您可以使用带有输出参数的匿名块并调用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()

【讨论】:

    【解决方案2】:

    很遗憾,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;
    

    【讨论】:

    • 是的,pity 不是我会用的词...谢谢,这是可行的,但由于我不得不在 .NET 端创建一个特殊功能,我会使用@T.S. 评论中的想法。以上(使用 OracleDbType.Long 的返回参数)。
    • AFAIU 这不适用于使用字符串文字形式 q'[ ... ]' 的视图,对吗?
    • 那是一个不错的选择。我在 WHERE 语句中添加了 OWNER,在循环中添加了 EXIT 语句,以明确我们只需要一行,并且将使用它。
    【解决方案3】:

    this 的另一种方法是(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
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 2015-01-23
      • 2014-12-27
      • 2013-07-09
      • 1970-01-01
      相关资源
      最近更新 更多