C#BulkCopy、DBFエラー(Timout、&Providerは判別できませんでした)

bulkinsert c# foxpro smo sqlbulkcopy

質問

DBF / FoxPoファイルを含むフォルダを指す小さなコンソールアプリケーションを作成しました。

次に、各dbf表に基づいてSQLで表を作成し、次にバルク・コピーを実行して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) "プロバイダーはDecimal値を判別できませんでした。たとえば、行が作成されたばかりで、Decimal列のデフォルトは使用できず、コンシューマーは新しいDecimal値をまだ設定していませんでした。

3) SqlDateTimeがオーバーフローします。 1/1/1753 12:00:00 AMと12/31/9999 11:59:59 PMの間である必要があります。

私は、問題の内容を示すgoogleの結果を見つけました: [A] ... [B]を回避する可能性のある作業(ただし、10進数の値を10進数で、日付は日付として保持したいと思います。データに対してさらに計算を行う)

解決策として私がしたいこと

1.)接続時間を増やしてください(ただし、それ以上に増やすことはできません)、あるいは、OleDbDataReaderの結果を分割してインクリメンタルな一括挿入で行うことが可能ですか?

2)バルクコピーでエラーが発生した結果を無視する可能性がある場合、またはエラーを記録したレコードをCSVファイルなどのログに記録するように考えていましたか?

受け入れられた回答

あなたが "for"ステートメントを実行する場所では、私はおそらく一度に多くのものを取るためにそれを分解するでしょう:

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"はインクリメンタルカウント(つまり、最大カウント)を記録し、 'バッチ'を作成したらテーブルを作成して一括コピーします。

それはあなたが期待するように見えますか?

乾杯、
クリス。


人気のある回答

これは私の現在の試みであり、バルクコピー方式ではテーブルの約90%で動作していますが、大きなテーブルでOutOfMemoryの例外を取得します...私は読者のデータをより小さなセションに分割したい、それをDataTableに渡してメモリに格納する必要はありません(大きな結果セットではOutOfMemory例外の原因になります)

更新

私のソリューションでどのように見えるかについて、以下のコードを改めました。私はいくつかのリファクタリングをdefし、私の答えを再び更新します。

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


ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ