Ошибки C # BulkCopy, DBF (тайм-аут & поставщик не может определить ...) - PullRequest
0 голосов
/ 02 февраля 2012

Я написал небольшое консольное приложение, которое указывает на папку, содержащую файлы DBF / FoxPo.

Затем оно создает таблицу в SQL на основе каждой таблицы dbf, затем выполняет массовую копию для вставкиданные в SQL.По большей части это работает довольно хорошо, за исключением нескольких ошибок.

1) Некоторые из таблиц FoxPro содержат 5000000+ записей, и соединение завершается до завершения вставки.

Здесьмоя строка подключения:

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

Сообщение об ошибке: "Время ожидания истекло. Время ожидания истекло до завершения операции, или сервер не отвечает."

КОД:

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

Мои 2-я и 3-я ошибки следующие:

Я понимаю, что такое проблемы, но как их исправитьих я не так уверен

2) "Поставщик не смог определить десятичное значение. Например, строка была только что создана, значение по умолчанию для столбца« Десятичное число »было недоступно, а потребительеще не установил новое десятичное значение. "

3) SqlDateTime переполнение.Должно быть между 01.01.1753 12:00:00 и 31.12.9999 23:59:59.

Я нашел результат в Google, который указал, в чем проблема: [A] ... и возможная работа вокруг [B] (но я бы хотел сохранить мои десятичные значения как десятичные, а даты как дату, как я буду делатьдальнейшие расчеты с данными)

Что я хочу сделать в качестве решения

1.) Либо увеличьте время соединения, (но я не думаю, что смогуувеличить его больше, чем у меня), или, в качестве альтернативы, возможно ли разделить результаты OleDbDataReader и сделать это при инкрементной массовой вставке?

2.) Я думал, возможно ли иметь массовую копию, чтобы игнорировать результаты с ошибкамиили у вас есть записи об ошибках, записываемые в CSV-файл или что-то в этом роде?

Ответы [ 2 ]

1 голос
/ 02 февраля 2012

Так что, где вы делаете утверждение "для", я бы, вероятно, разбил его на столько, сколько нужно:

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

Таким образом, «i» отслеживает общий счет, «j» отслеживает добавочный счет (т. Е. Ваш максимум за один раз), а когда вы создали «пакет», вы создаете таблицу и Bulk Copy это.

Это похоже на то, что вы ожидаете?

Приветствия
Крис.

0 голосов
/ 03 февраля 2012

Это мой текущий метод массового копирования, я не работаю примерно с 90% таблиц, но я получаю исключение OutOfMemory, с большими таблицами ... Я хотел бы разделить данные читателя наменьшие секции, без необходимости передавать его в DataTable и сначала сохранять его в памяти (что является причиной исключения OutOfMemory для больших наборов результатов)

UPDATE

Я изменил приведенный ниже код относительно того, как это выглядит в моем решении. Это не красиво ... но это работает.Я определенно сделаю рефакторинг и обновлю свой ответ снова.

    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("");
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...