3

使用ODP.Net托管API时,当使用数组绑定向VARCHAR2(4000)类型的列插入数据,而我们数组中某行值的字符串长度大于1000个字符时,抛出如下异常:

ORA-01461: 只能绑定 LONG 值以插入 LONG 列

string sql = "INSERT INTO STAGING(\"COLUMN1\") VALUES (:COLUMN1)";

using (OracleCommand cmd = connection.CreateCommand())
{
    cmd.CommandText = sql;
    cmd.CommandType = CommandType.Text;
    cmd.BindByName = true;
    cmd.ArrayBindCount = dt.Rows.Count;

    var p = new OracleParameter { ParameterName = parameterName.ToUpper() };
    p.OracleDbType = OracleDbType.Varchar2;
    p.Value = dt.AsEnumerable().Select(c => (!c.IsNull(fieldName) ? c.Field<T>(fieldName) : default(T))).ToArray();
    cmd.Parameters.Add(p);

    cmd.ExecuteNonQuery();
}

我们目前将参数定义为:

p.OracleDbType = OracleDbType.Varchar2;

我尝试改用它,但仍然遇到同样的问题:

p.OracleDbType = OracleDbType.Clob;

还尝试如下设置 Varchar2 的长度大小,但仍然存在相同的问题。

p.OracleDbType = OracleDbType.Varchar2;
p.Size = 4000;

也试过这个,没有运气:

string sql = "INSERT INTO STAGING(\"COLUMN1\") VALUES (CAST(:COLUMN1 AS VARCHAR2(4000))";

有任何想法吗?

这似乎是一个类似的问题:https ://community.oracle.com/thread/3649551

更新 我怀疑可能存在某种字符集问题,这使得长度比预期的要长,所以为了排除这种情况,我将我们试图插入数据的表的列长度减少到 VARCHAR2(1000 ),假设这将使最大允许字符长度为 250 - 但情况并非如此。在抛出此异常之前工作的最大值仍然是 1000。

更新 2 我找到了一个可以解决这个问题的 oracle 补丁。我将尝试获取此补丁并进行验证。https://support.oracle.com/epmos/faces/PatchDetail?patchId=20361140&requestId=18735492

更新 3 oracle 补丁没有为我解决这个问题。我尝试遍历所有参数绑定状态,但它们都表示成功。

catch (Exception ex)
{
    foreach (OracleParameter p in cmd.Parameters)
    {
        foreach (var s in p.ArrayBindStatus)
        {
            if (s != OracleParameterStatus.Success)
            {

            }
        }
    }
}

更新 4 似乎这是 Oracle Managed API 中的一个错误,这是一个可以重现该问题的示例类。

namespace OracleBindError
{
    using Oracle.ManagedDataAccess.Client;

    using System.Data;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            string testTable = "BIND_TEST_TABLE";
            string connString = "[conn string here]";

            string dropTable =
@"DECLARE pEXISTS NUMBER;
BEGIN
  SELECT COUNT(*) INTO pEXISTS FROM USER_TABLES WHERE TABLE_NAME = '" + testTable + @"';

  IF(pEXISTS > 0) THEN
    EXECUTE IMMEDIATE 'DROP TABLE " + testTable + @"';
  END IF;

  EXECUTE IMMEDIATE 'CREATE TABLE " + testTable + @" (COLUMN1 VARCHAR2(4000), COLUMN2 VARCHAR2(4000))';
END;";

            string[] greaterThanOneThousand = new string[] {
                        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkldfdffd",
            };

            string insertStatement = "INSERT INTO " + testTable + "(\"COLUMN1\",\"COLUMN2\") VALUES (:COLUMN1,:COLUMN2)";

            using (OracleConnection conn = new OracleConnection(connString))
            {
                conn.Open();

                OracleCommand dropCmd = new OracleCommand(dropTable, conn);
                dropCmd.ExecuteNonQuery();

                using (OracleCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = insertStatement;
                    cmd.CommandType = CommandType.Text;
                    cmd.BindByName = true;
                    cmd.ArrayBindCount = greaterThanOneThousand.Length;

                    var p = new OracleParameter { ParameterName = "COLUMN1" };
                    p.OracleDbType = OracleDbType.Varchar2;
                    p.Value = greaterThanOneThousand.ToArray();
                    cmd.Parameters.Add(p);

                    var p2 = new OracleParameter { ParameterName = "COLUMN2" };
                    p2.OracleDbType = OracleDbType.Varchar2;
                    p2.Value = new string[] { null };
                    cmd.Parameters.Add(p2);

                    cmd.ExecuteNonQuery();
                }

                conn.Close();
            }
        }
    }
}

找到解决 方法如果我在参数中将 OracleDbType 从 Varchar2 更改为 NVarchar2 ,它就可以工作。

var p = new OracleParameter { ParameterName = "COLUMN1" };
p.OracleDbType = OracleDbType.NVarchar2;
p.Value = greaterThanOneThousand.ToArray();
cmd.Parameters.Add(p);

var p2 = new OracleParameter { ParameterName = "COLUMN2" };
p2.OracleDbType = OracleDbType.Varchar2;
p2.Value = new string[] { " " };
cmd.Parameters.Add(p2);

解决方法 解决方法是在 .net 端的参数中使用 NVARCHAR2

4

1 回答 1

0

您正在将“T”类型的数组分配给值。然而,数据库期望它是 VARCHAR2(4000),相当于字符串。尝试将值转换为字符串。

于 2015-04-09T15:01:00.843 回答