11

我们的项目最近更新到了较新的 Oracle.ManagedDataAccess DLL (v 4.121.2.0),这个错误一直在间歇性地出现。我们已经修复了几次,但并不知道我们做了什么来修复它。

我相当肯定这是由于 CLOB 字段被映射到实体框架中的字符串,然后在 LINQ 语句中被选中,从而拉动整个实体,而不仅仅是一组有限的属性。

错误:

Value cannot be null.
Parameter name: byteArray

堆栈跟踪:

   at System.BitConverter.ToString(Byte[] value, Int32 startIndex, Int32 length)
   at OracleInternal.TTC.TTCLob.GetLobIdString(Byte[] lobLocator)
   at OracleInternal.ServiceObjects.OracleDataReaderImpl.CollectTempLOBsToBeFreed(Int32 rowNumber)
   at Oracle.ManagedDataAccess.Client.OracleDataReader.ProcessAnyTempLOBs(Int32 rowNumber)
   at Oracle.ManagedDataAccess.Client.OracleDataReader.Read()
   at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead()

可疑实体属性:

'Mapped to Oracle CLOB Column'
<Column("LARGEFIELD")>
Public Property LargeField As String

但我相信这是映射每个 Oracle 矩阵的字段的正确方法:

ODP.NET 类型概述

生成的 SQL 语句也没有明显错误:

SELECT 
...
"Extent1"."LARGEFIELD" AS "LARGEFIELD",
...
FROM ... "Extent1"
WHERE ...

根据 Ozkan 的建议,我也尝试了这个 Fluent 代码,但它似乎并没有影响我的情况。

modelBuilder.Entity(Of [CLASS])().Property(
    Function(x) x.LargeField
).IsOptional()

故障排除更新:

经过广泛的测试,我们非常确定这实际上是一个错误,而不是配置问题。在一组非常特定的情况下,导致问题的似乎是 CLOB 的内容。我已经在Oracle 论坛上交叉发布了这个,希望获得更多信息。

4

6 回答 6

2

安装 Oracle12 客户端后,我们遇到了同样的问题。在 machine.config (C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config) 中,我使用 Oracle.ManagedDataAccess 删除了所有条目。在目录 C:\Windows\Microsoft.NET\assembly\GAC_MSIL 中,我删除了 Oracle.ManagedDataAccess 和 Policy.4.121.Oracle.ManagedDataAccess。然后我的 C# 程序开始正常工作,使用它自己目录中的 Oracle.ManagedDataAccess dll。

于 2016-12-28T14:05:23.487 回答
1

一个小时前,我们在项目中遇到了这个问题,并找到了解决方案。由于 CLOB caolum 中的空值,它会生成此错误。我们有一个 CLOB 列,它在数据库中为 Nullable。在 EntityFramework 模型中,它是 String 但不是 Nullable。我们在 EF 模型中将列的 Nullable 属性更改为 True 并解决了问题。

于 2015-02-19T14:32:25.373 回答
1

我花了很多时间试图破译这一点,并在互联网上到处找到一些这样和那样的东西,但没有一个地方能把所有东西都放在一个地方,所以我想发布我学到的东西,以及我是如何解决的它,这很像 Ragowit 的答案,但我有它的 C# 代码。

背景

错误: 所以我的while (dr.Read())线路上有这个错误:

Value cannot be null. \r\nParmeter name: byteArray

我在互联网上遇到的这个问题很少,除了CLOB当它为空时该字段出现错误,并且据推测在最新的 ODAC 版本中已修复,据此: https ://community.oracle.com/thread /3944924

我对此的看法——不正确!它自 2015 年 10 月 5 日 ( http://www.oracle.com/technetwork/topics/dotnet/utilsoft-086879.html ) 以来一直没有更新,我使用的 12c 软件包是在 2016 年 4 月下载的。

其他人的完整堆栈跟踪几乎反映了我的错误:http: //pastebin.com/24AfFDnq

Value cannot be null.
Parameter name: byteArray

at System.BitConverter.ToString(Byte[] value, Int32 startIndex, Int32 length)
at OracleInternal.TTC.TTCLob.GetLobIdString(Byte[] lobLocator)
at OracleInternal.ServiceObjects.OracleDataReaderImpl.CollectTempLOBsToBeFreed(Int32 rowNumber)
at Oracle.ManagedDataAccess.Client.OracleDataReader.ProcessAnyTempLOBs(Int32 rowNumber)
at Oracle.ManagedDataAccess.Client.OracleDataReader.Read()
at     System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead()

'Mapped to Oracle CLOB Column'
<Column("LARGEFIELD")>
Public Property LargeField As String

'Mapped to Oracle BLOB Column'
<Column("IMAGE")>
Public Property FileContents As Byte()

我是怎么遇到的: 那是在阅读一个大约 3000 行的 11 列表时。其中一列实际上是一个NCLOB(显然这与 一样容易受到影响CLOB),它允许数据库中的空值,并且它的一些值是空的 - 毕竟它是一个可选的“Notes”字段。有趣的是,在注释字段为空的第一行甚至第二行上我都没有收到此错误。根据从 0 开始的计数器变量,直到第 768 行完成并且它即将开始第 769 行,它才出现错误int,我设置并查看了我的 DataTable 到目前为止有多少行。如果我使用,我发现我得到了错误:

DataSet ds = new DataSet();
OracleDataAdapter adapter = new OracleDataAdapter(cmd);
adapter.Fill(ds);

以及如果我使用:

DataTable dt = new DataTable();
OracleDataReader dr = cmd.ExecuteReader();
dt.Load(dr);

或者如果我使用:

OracleDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
     while (dr.Read())
     {
         ....
     }
}

cmd是哪里OracleCommand,所以没有区别。

分辨率

以下基本上是我用来解析OracleDataReader值以便将它们分配给DataTable. 它实际上并没有像它可能的那样精致 - 我使用它只是在所有情况下都返回dr[i]datarow除了当值为空时,当它是第十一列(索引 = 10,因为它从 0 开始)和一个特定的查询已被执行,以便我知道我的NCLOB专栏在哪里。

public static DataTable GetDataTableManually(string query)
{
    OracleConnection conn = null;
    try
    {
        string connString = ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString;
        conn = new OracleConnection(connString);
        OracleCommand cmd = new OracleCommand(query, conn);
        conn.Open();
        OracleDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        DataTable dtSchema = dr.GetSchemaTable();
        DataTable dt = new DataTable();

        List<DataColumn> listCols = new List<DataColumn>();
        List<DataColumn> listTypes = new List<DataColumn>();

        if (dtSchema != null)
        {
            foreach (DataRow drow in dtSchema.Rows)
            {
                string columnName = System.Convert.ToString(drow["ColumnName"]);
                DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
                listCols.Add(column);
                listTypes.Add(drow["DataType"].ToString());   // necessary in order to record nulls
                dt.Columns.Add(column);
            }
        }

        // Read rows from DataReader and populate the DataTable
        if (dr.HasRows)
        {
            int rowCount = 0;
            while (dr.Read())
            {            
                string fieldType = String.Empty;
                DataRow dataRow = dt.NewRow();

                for (int i = 0; i < dr.FieldCount; i++)
                {
                    if (!dr.IsDBNull[i])
                    {
                        fieldType = dr.GetFieldType(i).ToString(); // example only, this is the same as listTypes[i], and neither help us distinguish NCLOB from NVARCHAR2 - both will say System.String

                        // This is the magic
                        if (query == "SELECT * FROM Orders" && i == 10)
                            dataRow[((DataColumn)listCols[i])] = dr.GetOracleClob(i);  // <-- our new check!!!!
                        // Found if you have null Decimal fields, this is 
                        // also needed, and GetOracleDecimal and GetDecimal
                        // will not help you - only GetFloat does
                        else if (listTypes[i] == "System.Decimal")
                            dataRow[((DataColumn)listCols[i])] = dr.GetFloat(i);
                        else
                            dataRow[((DataColumn)listCols[i])] = dr[i];
                    }
                    else  // value was null; we can't always assign dr[i] if DBNull, such as when it is a number or decimal field
                    {
                        byte[] nullArray = new byte[0];
                        switch (listTypes[i])
                        {
                            case "System.String": // includes NVARCHAR2, CLOB, NCLOB, etc.
                                dataRow[((DataColumn)listCols[i])] = String.Empty;
                            break;
                            case "System.Decimal":
                            case "System.Int16":  // Boolean
                            case "System.Int32":  // Number
                                dataRow[((DataColumn)listCols[i])] = 0;
                            break;
                            case "System.DateTime":
                                dataRow[((DataColumn)listCols[i])] = DBNull.Value;
                            break;
                            case "System.Byte[]":  // Blob
                                dataRow[((DataColumn)listCols[i])] = nullArray;
                            break;
                            default:
                                dataRow[((DataColumn)listCols[i])] = String.Empty;
                            break;
                        }
                   }
               }
               dt.Rows.Add(dataRow);
           }
           ds.Tables.Add(dt);
       }

    }
    catch (Exception ex)
    {
        // handle error
    }
    finally
    {
        conn.Close();
    }

    // After everything is closed
    if (ds.Tables.Count > 0)
        return ds.Tables[0]; // there should only be one table if we got results
    else
        return null;

}

就像我让它根据在模式表循环中找到的列类型分配特定类型的空值一样,您可以将条件添加到“非空”端if...then并在那里执行各种GetOracle...语句。不过,我发现它仅在这种NCLOB情况下是必需的。

为了在信用到期时给予信用,原始代码库基于 sarathkumar 在Populate data table from data reader 中给出的答案。

于 2016-11-18T22:37:06.487 回答
1

我们在某些计算机上也遇到了这个问题,我们正在运行最新的 Oracle.ManagedDataAccess.dll (4.121.2.20150926 ODAC RELEASE 4)。

我们找到了解决问题的方法,我只想分享。

这是我们在某些计算机上出现的问题。

Using connection As New OracleConnection(yourConnectionString)
    Dim command As New OracleCommand(yourQuery, connection)
    connection.Open()

    Using reader As OracleDataReader = command.ExecuteReader()
        Dim clobField As String = CStr(reader.Item("CLOB_FIELD"))
    End Using

    connection.Close()
End Using

这是使它适用于所有计算机的解决方案。

Using connection As New OracleConnection(yourConnectionString)
    Dim command As New OracleCommand(yourQuery, connection)
    connection.Open()

    Using reader As OracleDataReader = command.ExecuteReader()
        Dim clobField As String = reader.GetOracleClob(0).Value
    End Using

    connection.Close()
End Using
于 2016-11-02T10:34:16.063 回答
0

对我来说这很简单!我在使用 odac v 4.121.1.0 时遇到了这个错误。我刚刚使用 Nuget 将 Oracle.ManagedDataAccess 更新为 4.121.2.0,现在它正在运行。

您是否尝试过使用 Nugget 卸载并重新安装 Oracle.ManagedDataAccess?

于 2016-04-14T14:36:31.660 回答
0

将 Oracle.ManagedDataAccess.dll 升级到版本 4.122.1.0 已解决。如果您使用的是 vs 2017,我们可以通过 NuGet 进行更新。

在此处输入图像描述

于 2018-05-21T13:03:12.393 回答