ODP.Net托管API - 使用字符串进行数组绑定> 1000个字符

时间:2015-04-08 17:43:22

标签: c# oracle oracle11g odp.net odp.net-managed

使用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。

1 个答案:

答案 0 :(得分:0)

您正在分配类型数组&#34; T&#34;变得有价值。然而,数据库期望它是VARCHAR2(4000),这相当于字符串。尝试将值转换为字符串。