我写了一个小型控制台应用程序,指向包含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" />
错误讯息: “超时已过期。操作完成前经过的超时时间或服务器没有响应。”
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();
}
}
}
我的第二个&amp;第三个错误如下:
我明白问题是什么,但如何纠正它们我不太确定
2)“提供程序无法确定Decimal值。例如,行刚刚创建,Decimal列的默认值不可用,并且消费者尚未设置新的Decimal值。”
3) SqlDateTime溢出。必须在1/1/1753 12:00:00 AM和12/31/9999 11:59:59 PM之间。
我在谷歌上发现了一个结果,表明问题所在:[A] ...以及可能解决[B]的问题(但我希望将我的小数值保留为十进制和日期作为日期,因为我将对数据进行进一步的计算)
我想要做的解决方案
1。)要么增加连接时间,(但我不认为我可以增加它比我更多),或者是否可以拆分OleDbDataReader的结果并进行增量批量插入?
2.)我在考虑是否可以使用批量复制来忽略带有错误的结果,或者将错误输出的记录记录到csv文件或某种程度的东西?
答案 0 :(得分:1)
所以,在你做“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”跟踪增量计数(即一次计数的最大值),当您创建“批处理”时,创建表格和批量复制它
这看起来像你期望的那样吗?
干杯,
克里斯。
答案 1 :(得分:0)
这是我在批量复制方法中的当前版本,我不适用于大约90%的表,但我得到一个OutOfMemory例子,更大的表...我想把读者的数据分成较小的部分,无需将其传递到DataTable并首先将其存储在内存中(这是更大结果集上OutOfMemory异常的原因)
<强>更新强>
修改了下面的代码,看看它在我的解决方案中看起来如何......它不是很好......但是它有效。我会做一些重构,然后再次更新我的答案。
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("");
}