1

我正在使用 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 个小数位问题的值,但在这些情况下我根本无法从数据读取器中读取。我原以为我可以在有问题的行上使用 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

4 回答 4

0

我不记得 FoxPro 有这个问题的原因。我认为这与数字的存储方式有关。无论如何,解决方案是(A)清理数据或(B)重新调整字段大小以允许更大的值。下面的示例代码演示了该问题。

* 创建一个可以存储 -0.99 和 99.99 之间的值的表
创建表“TEST.DBF”(av_length N(4,2))

* 在 1.10 和 22,222.22222 之间插入值
插入“测试”(av_length)值(1.1)
插入“测试”(av_length)值(2.2)
插入“测试”(av_length)值(11.11)
插入“测试”(av_length)值(22.22)
插入“测试”(av_length)值(111.111)
插入“测试”(av_length)值(222.222)
插入“测试”(av_length)值(1111.1111)
插入“测试”(av_length)值(2222.2222)
插入“测试”(av_length)值(11111.11111)
插入“测试”(av_length)值(22222.22222)

* 查看表格内容
* 注意记录 3 到 10 与字段定义不匹配
浏览正常

IF MESSAGEBOX("修复数据?选择更改字段定义", 0+4+32) = 6
    * 方案A:修复数据,重新查看表格内容
    在“测试”中用 MIN(av_length, 9.99) 替换所有 av_length
    浏览正常
别的
    * 方案B:更改字段定义,重新查看表格内容
    * 请注意,记录 9 和 10 仍需要修复
    ALTER TABLE "TEST.DBF" ALTER COLUMN av_length N(12,6)
    浏览正常
万一
于 2010-12-01T14:42:04.450 回答
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]; 

您显然也可以测试其他类型...

于 2010-11-29T14:29:21.207 回答
0

我不知道您是否可以获取 Visual Foxpro,但它有一个升级的“向导”,可以直接上传到 SQL Server。

它看起来像是通过 下载 Visual Foxpro 9、SP2在 MS 上免费下载试用

这可能是无法正确解释的 memo / blob 类型列的问题。

于 2010-11-25T12:44:14.273 回答
0

从您列出的表格结构来看,这是正确的。在列出的表结构的 VFP 中,AV_LENGTH 是数字类型,长度为 4,为小数位分配 2。所以它的值最多为“9.99”。VFP 强制数字字段的输入最多为 2 个小数位,1 个用于小数点,其余为整数部分。

其余基于数字的字段是具有长度的数字,但没有小数位,这表明它们都是没有小数位的整数,因此可以作为整数数据类型。带小数的数字应为浮点或双列类型。

话虽如此,我不知道您是如何在数字 4、2 十进制中获得 10.0 值的。这是我第一次看到强制一个大于所保存结构的分配意图的数字实际上存储在这样的字段中。

于 2010-11-30T12:39:49.910 回答