BulkCopy C #, erreurs DBF (Timout, & Provider n'a pas pu déterminer ...)

bulkinsert c# foxpro smo sqlbulkcopy

Question

J'ai écrit une petite application de console qui pointe vers un dossier contenant des fichiers DBF / FoxPo.

Il crée ensuite une table SQL basée sur chaque table DBF, puis effectue une copie en bloc pour insérer les données dans SQL. Cela fonctionne assez bien pour la plupart, à l'exception de quelques accrocs.

1) Certaines tables FoxPro contiennent plus de 500 000 enregistrements et la connexion expire avant la fin de l'insertion.

Voici ma chaîne de connexion:

<add name="SQL" connectionString="data source=source_source;persist security info=True;user id=DBFToSQL;password=DBFToSQL;Connection Timeout=20000;Max Pool Size=200" providerName="System.Data.SqlClient" />

Message d'erreur: "Le délai d'attente a expiré. Le délai d'attente s'est écoulé avant la fin de l'opération ou le serveur ne répond pas."

CODE:

using (SqlConnection SQLConn = new SqlConnection(SQLString))
using (OleDbConnection FPConn = new OleDbConnection(FoxString))
{
    ServerConnection srvConn = new Microsoft.SqlServer.Management.Common.ServerConnection(SQLConn);
    try
    {
        FPConn.Open();                       
        string dataString = String.Format("Select * from {0}", tableName);

        using (OleDbCommand Command = new OleDbCommand(dataString, FPConn))
        using (OleDbDataReader Reader = Command.ExecuteReader(CommandBehavior.SequentialAccess))
        {                       
            tbl = new Table(database, tableName, "schema");

            for (int i = 0; i < Reader.FieldCount; i++)
            {                           
                col = new Column(tbl, Reader.GetName(i), ConvertTypeToDataType(Reader.GetFieldType(i)));
                col.Nullable = true;
                tbl.Columns.Add(col);                       
            }

            tbl.Create();                       
            BulkCopy(Reader, tableName);
        }                   
    }
    catch (Exception ex)
    {
       // LogText(ex, @"C:\LoadTable_Errors.txt", tableName);
        throw ex;
    }
    finally
    {
        SQLConn.Close();
        srvConn.Disconnect();
    }
}

private DataType ConvertTypeToDataType(Type type)
{
    switch (type.ToString())
    {
        case "System.Decimal":
            return DataType.Decimal(18, 38);
        case "System.String":
            return DataType.NVarCharMax;
        case "System.Int32":
            return DataType.Int;
        case "System.DateTime":
            return DataType.DateTime;
        case "System.Boolean":
            return DataType.Bit;
        default:
            throw new NotImplementedException("ConvertTypeToDataType Not implemented for type : " + type.ToString());
    }
}

 private void BulkCopy(OleDbDataReader reader, string tableName)
{
    using (SqlConnection SQLConn = new SqlConnection(SQLString))
    {       
        SQLConn.Open();
        SqlBulkCopy bulkCopy = new SqlBulkCopy(SQLConn);

        bulkCopy.DestinationTableName = "schema." + tableName;

        try
        {
            bulkCopy.WriteToServer(reader);         
        }
        catch (Exception ex)
        {           
            //LogText(ex, @"C:\BulkCopy_Errors.txt", tableName);
        }
        finally
        {
            SQLConn.Close();
            reader.Close();
        }
    }
}

Mes 2ème et 3ème erreurs sont les suivantes:

Je comprends quels sont les problèmes, mais comment les corriger, je ne suis pas si sûr

2) "Le fournisseur n'a pas pu déterminer la valeur décimale. Par exemple, la ligne vient d'être créée, la valeur par défaut de la colonne décimale n'est pas disponible et le consommateur n'a pas encore défini de nouvelle valeur décimale."

3) débordement de SqlDateTime. Doit être entre 1/1/1753 00:00:00 et 12/31/9999 23:59:59 PM.

J'ai trouvé sur Google un résultat indiquant la nature du problème: [A] ... et un travail possible autour de [B] (mais j'aimerais conserver mes valeurs décimales sous forme décimale et mes dates sous forme de date, effectuer d'autres calculs par rapport aux données)

Ce que je veux faire comme solution

1.) Soit augmenter le temps de connexion (mais je ne pense pas que je puisse l’augmenter plus que ce que j’ai), ou bien est-il possible de scinder les résultats de OleDbDataReader et de les insérer en bloc de manière incrémentielle?

2.) Je me demandais s’il était possible d’utiliser une copie en bloc pour ignorer les résultats contenant des erreurs, ou si les enregistrements qui font erreur se logent dans un fichier CSV ou quelque chose de ce genre?

Réponse acceptée

Donc, là où vous faites la déclaration "pour", je la scinderais probablement pour en prendre plusieurs à la fois:

int i = 0;
int MaxCount = 1000;

while (i < Reader.FieldCount)
{
    var tbl = new Table(database, tableName, "schema"); 

    for (int j = i; j < MaxCount; j++) 
    {                            
        col = new Column(tbl, Reader.GetName(j), ConvertTypeToDataType(Reader.GetFieldType(j))); 
        col.Nullable = true; 
        tbl.Columns.Add(col);
        i++;                      
    } 

    tbl.Create();                        
    BulkCopy(Reader, tableName); 
}

Ainsi, "i" garde une trace du compte global, "j" garde une trace du compte incrémentiel (c'est-à-dire votre compte maximum à un moment donné) et lorsque vous avez créé votre "lot", vous créez la table et la copie en bloc.

Cela ressemble-t-il à ce que vous attendez?

À votre santé,
Chris.


Réponse populaire

C’est ce que je fais actuellement à la méthode de la copie groupée, je ne travaille pas pour environ 90% des tables, mais j’obtiens une exception OutOfMemory, avec les tables plus grandes ... Je voudrais scinder les données du lecteur en parties plus petites, sans avoir à le passer dans un DataTable et à le stocker en mémoire d'abord (ce qui est la cause de l'exception OutOfMemory sur les ensembles de résultats plus grands)

METTRE À JOUR

J'ai modifié le code ci-dessous quant à son apparence dans ma solution. Ce n'est pas joli, mais ça marche. Je vais définitivement refactoriser et mettre à jour ma réponse.

    private void BulkCopy(OleDbDataReader reader, string tableName, Table table)
    {
        Console.WriteLine(tableName + " BulkCopy Started.");
        try
        {
            DataTable tbl = new DataTable();
            List<Type> typeList = new List<Type>();
            foreach (Column col in table.Columns)
            {
                tbl.Columns.Add(col.Name, ConvertDataTypeToType(col.DataType));
                typeList.Add(ConvertDataTypeToType(col.DataType));
            }

            int batch = 1;
            int counter = 0;

            DataRow tblRow = tbl.NewRow();

            while (reader.Read())
            {
                counter++;
                int colcounter = 0;
                foreach (Column col in table.Columns)
                {
                    try
                    {
                        tblRow[colcounter] = reader[colcounter];
                    }
                    catch (Exception)
                    {
                        tblRow[colcounter] = GetDefault(typeList[0]);
                    }
                    colcounter++;
                }

                tbl.LoadDataRow(tblRow.ItemArray, true);

                if (counter == BulkInsertIncrement)
                {
                    Console.WriteLine(tableName + " :: Batch >> " + batch);
                    counter = PerformInsert(tableName, tbl, batch);
                    batch++;
                }
            }

            if (counter > 0)
            {
                Console.WriteLine(tableName + " :: Batch >> " + batch);
                PerformInsert(tableName, tbl, counter);
            }

            tbl = null;
            Console.WriteLine("BulkCopy Success!");
        }
        catch (Exception ex)
        {
            Console.WriteLine("BulkCopy Fail!");
            SharedLogger.Write(ex, @"C:\BulkCopy_Errors.txt", tableName);
            Console.WriteLine(ex.Message);
        }
        finally
        {
            reader.Close();
            reader.Dispose();

        }
        Console.WriteLine(tableName + " BulkCopy Ended.");
        Console.WriteLine("*****");
        Console.WriteLine("");
    }


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi