我使用FoxPro OLE-DB驱动程序将一些数据从FoxPro数据库导入到Sql Server数据库。我正在采取的方法是遍历FoxPro表,选择所有记录到DataTable,然后使用SqlBulkCopy将该表插入到Sql Server中。除了我收到以下错误的几个实例之外,这种方法很好:
System.InvalidOperationException: The provider could not determine the Decimal value. For example, the row was just created, the default for the Decimal column was not available, and the consumer had not yet set a new Decimal value.
我已经对此进行了调查,并记录了它出现的哪些行,问题是FoxPro表具有固定的数值宽度。 1存储为1.00但是10存储为10.0,它是引起问题的小数点后的单个数字。现在我已经找到了这个问题,但我正努力解决这个问题。我正在使用以下函数将OLEDBReader转换为DataTable:
private DataTable FPReaderToDataTable(OleDbDataReader dr, string TableName)
{
DataTable dt = new DataTable();
//get datareader schema
DataTable SchemaTable = dr.GetSchemaTable();
List<DataColumn> cols = new List<DataColumn>();
if (SchemaTable != null)
{
foreach (DataRow drow in SchemaTable.Rows)
{
string columnName = drow["ColumnName"].ToString();
DataColumn col = new DataColumn(columnName, (Type)(drow["DataType"]));
col.Unique = (bool)drow["IsUnique"];
col.AllowDBNull = (bool)drow["AllowDBNull"];
col.AutoIncrement = (bool)drow["IsAutoIncrement"];
cols.Add(col);
dt.Columns.Add(col);
}
}
//populate data
int RowCount = 1;
while (dr.Read())
{
DataRow row = dt.NewRow();
for (int i = 0; i < cols.Count; i++)
{
try
{
row[((DataColumn)cols[i])] = dr[i];
}
catch (Exception ex) {
if (i > 0)
{
LogImportError(TableName, cols[i].ColumnName, RowCount, ex.ToString(), dr[0].ToString());
}
else
{
LogImportError(TableName, cols[i].ColumnName, RowCount, ex.ToString(), "");
}
}
}
RowCount++;
dt.Rows.Add(row);
}
return dt;
}
我想要做的是检查具有1位小数位的问题但在这些情况下我根本无法从datareader读取。我原本以为我可以在有问题的行上使用dr.GetString(i)但是这会返回以下错误:
The provider could not determine the String value. For example, the row was just created, the default for the String column was not available, and the consumer had not yet set a new String value.
我无法更新FoxPro数据,因为该列不允许这样做,如何从DataReader读取记录并修复它?我已经尝试了所有cast / dr.GetValue / dr.GetData的组合,并且都给出了相同错误的变体。
FoxPro表的结构如下:
Number of data records: 1664
Date of last update: 11/15/10
Code Page: 1252
Field Field Name Type Width Dec Index Collate Nulls Next Step
1 AV_KEY Numeric 6 Asc Machine No
2 AV_TEAM Numeric 6 No
3 AV_DATE Date 8 No
4 AV_CYCLE Numeric 2 No
5 AV_DAY Numeric 1 No
6 AV_START Character 8 No
7 AV_END Character 8 No
8 AV_SERVICE Numeric 6 No
9 AV_SYS Character 1 No
10 AV_LENGTH Numeric 4 2 No
11 AV_CWEEKS Numeric 2 No
12 AV_CSTART Date 8 No
** Total ** 61
导致问题的是av_length列
答案 0 :(得分:0)
我不知道你是否有权获得Visual Foxpro,但它有一个升级的“向导”,可以直接上传到SQL Server。
通过Download Visual Foxpro 9, SP2
在MS上试用免费下载对于未正确解释的memo / blob类型列可能存在问题。
答案 1 :(得分:0)
你提到了类型转换,但不确定你是怎么尝试的......在你的try / catch中
row[((DataColumn)cols[i])] = dr[i];
您可能希望显式测试列数据类型并强制它...类似于(不是下面的DataType.ToString()的对象引用的正面,但您必须在运行/调试期间找到它。
if( cols[i].DataType.ToString().ToLower().Contains( "int" ))
row[((DataColumn)cols[i])] = (int)dr[i];
else
row[((DataColumn)cols[i])] = dr[i];
你显然也可以测试其他类型......
答案 2 :(得分:0)
从列出的表格结构来看,它正在做什么。在VFP中列出的表结构中,AV_LENGTH的类型为numeric,长度为4,2为十进制位分配。因此它在MOST的值为“9.99”。 VFP强制数字字段的输入最多为2个小数位,1表示小数点,其余为整数部分。
其余的基于数字的字段是带有长度的数字,但是没有小数位,表示它们都是没有小数位的全数,因此可以作为整数数据类型。带小数的数字应该是浮点数或双列类型。
话虽如此,我不知道你是如何得到一个数字4,2十进制的10.0值。这是我第一次看到强制大于被保存结构的分配意图的数字实际存储在这样的字段中。
答案 3 :(得分:0)
我不记得FoxPro有这个问题的原因。我认为它与数字的存储方式有关。无论如何,解决方案是(A)清理数据或(B)重新调整字段大小以允许更大的值。下面的示例代码演示了这个问题。
* create a table that can store a value between -0.99 and 99.99 CREATE TABLE "TEST.DBF" (av_length N(4,2)) * insert values between 1.10 and 22,222.22222 INSERT INTO "TEST" (av_length) VALUES(1.1) INSERT INTO "TEST" (av_length) VALUES(2.2) INSERT INTO "TEST" (av_length) VALUES(11.11) INSERT INTO "TEST" (av_length) VALUES(22.22) INSERT INTO "TEST" (av_length) VALUES(111.111) INSERT INTO "TEST" (av_length) VALUES(222.222) INSERT INTO "TEST" (av_length) VALUES(1111.1111) INSERT INTO "TEST" (av_length) VALUES(2222.2222) INSERT INTO "TEST" (av_length) VALUES(11111.11111) INSERT INTO "TEST" (av_length) VALUES(22222.22222) * view the contents of the table * note that records 3 to 10 do not match the field definition BROWSE NORMAL IF MESSAGEBOX("Fix the Data? Select to Change the Field Definition", 0+4+32) = 6 * Solution A: fix the data, and view the table contents again REPLACE ALL av_length WITH MIN(av_length, 9.99) IN "TEST" BROWSE NORMAL ELSE * Solution B: change the field definition, and view the table contents again * note that records 9 & 10 still need to be fixed ALTER TABLE "TEST.DBF" ALTER COLUMN av_length N(12,6) BROWSE NORMAL ENDIF