C # BulkCopy, DBF-Fehler (Timout & Provider konnte nicht ermitteln ...)

bulkinsert c# foxpro smo sqlbulkcopy

Frage

Ich habe eine kleine Konsolen-App geschrieben, die ich auf einen Ordner mit DBF / FoxPo-Dateien zeige.

Es erstellt dann eine Tabelle in SQL basierend auf jeder DBF-Tabelle und erstellt dann eine Massenkopie, um die Daten in SQL einzufügen. Es funktioniert meistens ziemlich gut, abgesehen von ein paar Haken.

1) Einige der FoxPro-Tabellen enthalten mehr als 5000000 Datensätze und die Verbindung tritt auf, bevor die Einfügung abgeschlossen ist.

Hier ist meine Verbindungszeichenfolge:

<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" />

Fehlermeldung: "Timeout abgelaufen. Das Zeitlimit abgelaufen vor dem Abschluss der Operation oder der Server reagiert nicht."

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

Mein 2. und 3. Fehler sind folgende:

Ich verstehe, was die Probleme sind, aber wie man sie korrigiert, bin ich nicht so sicher

2) "Der Provider konnte den Decimal-Wert nicht ermitteln. Beispielsweise wurde die Zeile gerade erstellt, der Standardwert für die Dezimalspalte war nicht verfügbar und der Consumer hatte noch keinen neuen Decimal-Wert festgelegt."

3) SqlDateTime Überlauf. Muss zwischen dem 1. Januar 1753 12:00:00 Uhr und dem 31.12.9999 23:59:59 Uhr liegen.

Ich habe bei google ein Ergebnis gefunden, das auf das Problem hinweist: [A] ... und eine mögliche Umgehung [B] (aber ich möchte meine Dezimalwerte als Dezimalzahlen und Datumsangaben als Datum beibehalten machen weitere Berechnungen gegen die Daten)

Was ich als Lösung machen möchte

1.) Entweder erhöhen Sie die Verbindungszeit, (aber ich denke nicht, dass ich es mehr erhöhen kann, als ich habe), oder ist es alternativ möglich, die Ergebnisse des OleDbDataReader aufzuteilen und inkrementelle Massen einzufügen?

2.) Ich habe gedacht, wenn es möglich ist, Bulk-Kopie Ergebnisse mit Fehlern zu ignorieren, oder haben die Datensätze, die Fehler in einer CSV-Datei oder etwas in diesem Ausmaß protokollieren?

Akzeptierte Antwort

Also, wo du die "for" Aussage machst, würde ich es wahrscheinlich brechen, um so viele auf einmal zu nehmen:

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

Also, "i" verfolgt die Gesamtzählung, "j" verfolgt die inkrementelle Zählung (dh Ihre max zu einer Zeit zählen) und wenn Sie Ihre "Batch" erstellt haben, erstellen Sie die Tabelle und Bulk Copy es.

Sieht das so aus, wie Sie es erwarten würden?

Prost,
Chris.


Beliebte Antwort

Dies ist mein momentaner Versuch bei der Massenkopiermethode, ich arbeite für ungefähr 90% der Tabellen, aber ich bekomme eine OutOfMemory-Ausnahme mit den größeren Tabellen ... Ich möchte die Daten des Lesers in kleinere Teile teilen, ohne es in ein DataTable zu übergeben und es zuerst im Speicher zu speichern (was die Ursache der OutOfMemory-Ausnahme in den größeren Resultsets ist)

AKTUALISIEREN

Imodified den Code unten, wie es in meiner Lösung aussieht .. Es ist nicht schön .. aber es funktioniert. Ich werde def Refactoring tun und meine Antwort erneut aktualisieren.

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


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum