2010-12-13 62 views
2

J'essaye d'insérer en bloc quelques données dans un oracle db. J'ai suivi l'exemple dans la documentation.Pourquoi cet insert vrac Oracle ne fonctionne-t-il pas?

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(); 
} 

Eh bien, cela ne fonctionne pas. Rien n'est inséré dans la base de données, je ne reçois aucun message d'erreur. Tout fonctionne correctement lorsque je n'utilise pas l'insertion en bloc (à la place, je foreach-boucle à travers chaque ligne de mes DataTables et insérer le DataRow dans la base de données à chaque itération). MISE À JOUR: J'ai suivi les suggestions et apporté les modifications suivantes à mon paramètre.

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

Je reçois cette erreur:

System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Array'.
at Oracle.DataAccess.Client.OracleParameter.SetStatus(Int32 arraySize)
at Oracle.DataAccess.Client.OracleParameter.ResetCtx(Int32 arraySize)
at Oracle.DataAccess.Client.OracleParameter.PreBind(OracleConnection conn, IntPtr errCtx, Int32 arraySize)
at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()
at Gateway.DataGateway.Import(String connString, Product product) in \path\share$\Visual Studio 2010\Projects\ImportData-trunk\Gateway\DataGateway.Sql.cs:line 196

MAJ2: Le pilote ODP.NET est stupide (juste ne fonctionne pas comme j'exprected;)

cela ne fonctionne pas

var names = new List<string>(); 

cela doit être cela

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

Je ne sais pas pourquoi cela ne fonctionne pas, mais vous devriez essayer une ligne par ligne insérer d'abord pour voir si cela fonctionne. Aussi, avez-vous payé assez d'argent à Oracle? Cela pourrait faire partie du problème. ;) – poindexter12

+0

Il fonctionne rangée par rangée et mon employeur a payé oracle assez d'argent;) – mrt181

+0

c'est juste ce qui se passe quand vous avez une forte excrétion. –

Répondre

1

Je nous avais la méthode ToArray() sur la Liste.

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

Vous devez définir la propriété CollectionType sur OracleCollectionType.PLSQLAssociativeArray pour que les opérations groupées fonctionnent.

Comme il n'y a pas de méthode Add() qui vous permet de specificy cela, vous devez ajouter la ligne suivante après l'appel à Parameters.Add():

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

J'ai essayé de vous approcher et j'ai terminé avec ma mise à jour. ça ne marche toujours pas, mais maintenant je reçois un message d'erreur. – mrt181

+0

J'utilise ArrayBinding (exécute la commande x fois, je te donne toutes les valeurs avant de commencer l'exécution). Je n'ai pas besoin d'utiliser les propriétés CollectionType ou Size. – mrt181

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; 
    }