【问题标题】:Why does this oracle bulk insert not work?为什么这个 oracle 批量插入不起作用?
【发布时间】:2010-12-13 16:50:04
【问题描述】:

我正在尝试将一些数据批量插入到 oracle 数据库中。我按照文档中的示例进行操作。

this.DataBaseAccess = new OracleConnection(connString);
var dataAdapter = new OracleDataAdapter();
var insertCmd = DataBaseAccess.CreateCommand();
insertCmd.CommandType = CommandType.Text;
insertCmd.BindByName = true;

var names = new List<string>();

foreach (DataTable table in product.Contracts.Tables)
{
    foreach (DataRow row in table.Rows)
    {
        names.Add(row["Contract"].ToString());
    }

    const string InsertContracts = "merge into CONTRACT t " +
                                   "using " +
                                   "(select :name NAME from dual) s " +
                                   "on (t.NAME = s.NAME) " +
                                   "when not matched then " +
                                   "insert (t.NAME) " +
                                   "values (s.NAME)";

    insertCmd.CommandText = InsertContracts;
    insertCmd.ArrayBindCount = table.Rows.Count;
    insertCmd.Parameters.Add(":name", OracleDbType.Varchar2, names, ParameterDirection.Input);

    dataAdapter.InsertCommand = insertCmd;

    this.DataBaseAccess.Open();
    insertCmd.ExecuteNonQuery();
    this.DataBaseAccess.Close();
}

好吧,它不起作用。没有向数据库中插入任何内容,我没有收到任何错误消息。

当我不使用批量插入时,一切正常(相反,我对 DataTables 中的每一行进行 foreach 循环,并在每次迭代时将 DataRow 插入数据库)。

更新:我已按照建议对我的参数进行了以下更改。

var nameParam = new OracleParameter
    {
        ParameterName = ":name",
        OracleDbType = OracleDbType.Varchar2,
        Value = names,
        Size = table.Rows.Count,
        CollectionType = OracleCollectionType.PLSQLAssociativeArray,
        Direction = ParameterDirection.Input
    }; 

我收到此错误:

System.InvalidCastException:无法将“System.String”类型的对象转换为“System.Array”类型。
在 Oracle.DataAccess.Client.OracleParameter.SetStatus(Int32 arraySize)
在 Oracle.DataAccess.Client.OracleParameter.ResetCtx(Int32 arraySize)
在 Oracle.DataAccess.Client.OracleParameter.PreBind(OracleConnection conn, IntPtr errCtx, Int32 arraySize)
在 Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()
在 Gateway.DataGateway.Import(String connString, Product product) 在 \path\share$\Visual Studio 2010\Projects\ImportData-trunk\Gateway\DataGateway.Sql.cs:line 196

UPDATE2:ODP.NET 驱动程序很愚蠢(只是不能像我预期的那样工作;)

这不起作用

var names = new List<string>();

一定是这样的

var names = new string[table.Rows.Count];

【问题讨论】:

  • 不确定为什么这不起作用,但您应该先尝试逐行插入,看看是否有效。另外,你付给甲骨文足够的钱了吗?这可能是问题的一部分。 ;)
  • 它逐行运行,我的雇主确实向 oracle 支付了足够的钱;)
  • 当你有很高的期望时会发生这种情况。

标签: c# oracle bulkinsert odp.net


【解决方案1】:

您需要将参数CollectionType 属性设置为OracleCollectionType.PLSQLAssociativeArray 才能使批量操作生效。

由于没有 Add() 方法可以让您具体说明这一点,您必须在调用 Parameters.Add() 之后添加以下行:

insertCmd.Parameters[0].CollectionType = OracleCollectionType.PLSQLAssociativeArray

【讨论】:

  • 我试过你的方法并以我的更新结束。它仍然不起作用,但现在我收到一条错误消息。
  • 我正在使用 ArrayBinding(执行命令 x 次,在您开始执行之前我会为您提供所有值)。我不需要使用 CollectionType 或 Size 属性。
【解决方案2】:
private void BulkCopy(List<test_bulk> lsttest_bulk)
    {       
        try
        {
            //ConnectionString = String.Format("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1})))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={2})));User Id={3};Password={4};", "ServerAddress", "PortAddress", "DatabaseName", "Username", "Password");

            ConnectionString = String.Format("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1})))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={2})));User Id={3};Password={4};", "ServerAddress", "PortAddress", "DatabaseName", "Username", "Password");


            OracleConnection oraConn = new OracleConnection(ConnectionString);

            oraConn.Open();
            OracleCommand oraCMD = new OracleCommand();
            oraCMD.Connection = oraConn;



            var oracleBulkCopy = new OracleBulkCopy(oraConn)
            {
                DestinationTableName = "test_bulk",
                BulkCopyOptions = OracleBulkCopyOptions.UseInternalTransaction
            };

                DataTable oDataTable = GetDataTableFromObjects<test_bulk>(lsttest_bulk);

                oracleBulkCopy.WriteToServer(oDataTable);
                oracleBulkCopy.Dispose();
        }
        catch(Exception ex)
        {
            Console.WriteLine("failed to write:\t{0}", ex.Message);
        }
    }


    public static DataTable GetDataTableFromObjects<TDataClass>(List<TDataClass> dataList)
    where TDataClass : class
    {
        Type t = typeof(TDataClass);
        DataTable dt = new DataTable(t.Name);
        foreach (PropertyInfo pi in t.GetProperties())
        {
            dt.Columns.Add(new DataColumn(pi.Name));
        }
        if (dataList != null)
        {
            foreach (TDataClass item in dataList)
            {
                DataRow dr = dt.NewRow();
                foreach (DataColumn dc in dt.Columns)
                {
                    dr[dc.ColumnName] =
                      item.GetType().GetProperty(dc.ColumnName).GetValue(item, null);
                }
                dt.Rows.Add(dr);
            }
        }
        return dt;
    }

【讨论】:

    【解决方案3】:

    我不得不在 List 上使用 ToArray() 方法。

    insertCmd.Parameters.Add(":name", OracleDbType.Varchar2, names.ToArray(), ParameterDirection.Input);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 2016-09-24
      • 2019-01-06
      • 2011-06-15
      相关资源
      最近更新 更多