C # BulkCopy, DBF Errors (Timout, & Provider no pudo determinar ...)

bulkinsert c# foxpro smo sqlbulkcopy

Pregunta

He escrito una aplicación de consola pequeña que apunto a una carpeta que contiene archivos DBF / FoxPo.

Luego crea una tabla en SQL basada en cada tabla dbf, luego realiza una copia masiva para insertar los datos en SQL. Funciona bastante bien en su mayor parte, a excepción de algunos inconvenientes ..

1) Algunas de las tablas de FoxPro contienen más de 5000000 registros y la conexión expries antes de que se complete la inserción.

Aquí está mi cadena de conexión:

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

Mensaje de error: "Se agotó el tiempo de espera. El período de tiempo de espera transcurrió antes de completar la operación o el servidor no responde".

CÓDIGO:

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

Mis errores 2 y 3 son los siguientes:

Entiendo cuáles son los problemas, pero cómo rectificarlos no estoy tan seguro

2) "El proveedor no pudo determinar el valor decimal. Por ejemplo, la fila se acaba de crear, el valor predeterminado para la columna decimal no estaba disponible y el consumidor aún no había establecido un nuevo valor decimal".

3) SqlDateTime desbordamiento. Debe estar entre el 1/1/1753 12:00:00 AM y el 12/31/9999 11:59:59 PM.

Encontré un resultado en google que indicaba cuál es el problema: [A] ... y un posible trabajo alrededor de [B] (pero me gustaría mantener mis valores decimales como decimales y las fechas como fecha, como lo haré estar haciendo mas cálculos contra los datos)

Lo que quiero hacer como solución.

1.) O aumenta el tiempo de conexión (pero no creo que pueda aumentarlo más de lo que tengo), o ¿es posible dividir los resultados de OleDbDataReader y hacer una inserción masiva incremental?

2.) Estaba pensando si es posible tener una copia masiva para ignorar los resultados con errores, o si los registros que cometen errores inician sesión en un archivo csv o algo así.

Respuesta aceptada

Entonces, ¿dónde hace la declaración "para"? Probablemente la dividiría para tomar tantas a la vez:

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

Por lo tanto, "i" hace un seguimiento del recuento general, "j" hace un seguimiento del recuento incremental (es decir, su máximo en un recuento de tiempo) y cuando haya creado su 'lote', cree la tabla y la Copie a granel.

¿Se parece a lo que cabría esperar?

Aclamaciones,
Chris


Respuesta popular

Este es mi intento actual en el método de copia masiva, no trabajo para aproximadamente el 90% de las tablas, pero obtengo una excepción OutOfMemory, con las tablas más grandes ... Me gustaría dividir los datos del lector en secciones más pequeñas, sin tener que pasarlo a un DataTable y almacenarlo en la memoria primero (que es la causa de la excepción OutOfMemory en los conjuntos de resultados más grandes)

ACTUALIZAR

Imodifiqué el código a continuación en cuanto a cómo se ve en mi solución ... No es bastante ... pero funciona. Definitivamente haré un poco de refactorización y actualizaré mi respuesta nuevamente.

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


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué