使用FoxPro OLEDB驱动程序导入数据时出错

时间:2010-11-24 16:58:12

标签: c# visual-foxpro

我使用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列

4 个答案:

答案 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