Ошибка импорта данных с драйвером FoxPro OLEDB - PullRequest
1 голос
/ 24 ноября 2010

Я импортирую некоторые данные из базы данных FoxPro в базу данных Sql Server, используя драйвер FoxPro OLE-DB. Подход, который я использую, состоит в том, чтобы пройтись по таблицам 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 и исправить ее? Я перепробовал все комбинации casting / 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 голосов
/ 01 декабря 2010

Я не помню причину, почему 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
0 голосов
/ 29 ноября 2010

Вы упомянули приведение типов, но не знаете, как вы пытались это сделать ... В вашем try / catch, где у вас есть

 row[((DataColumn)cols[i])] = dr[i]; 

Возможно, вы захотите явно проверить тип данных столбцов и FORCE его ... что-то вроде (не является положительным для ссылки на объект для DataType.ToString () ниже, но вы должны будете найти это во время выполнения / отладки.

if( cols[i].DataType.ToString().ToLower().Contains( "int" ))
     row[((DataColumn)cols[i])] = (int)dr[i]; 
else
     row[((DataColumn)cols[i])] = dr[i]; 

Очевидно, вы могли бы проверить и другие типы ...

0 голосов
/ 30 ноября 2010

Из приведенной вами структуры таблицы, это ПРАВИЛЬНО, что она делает. В VFP для перечисленной структуры таблицы AV_LENGTH имеет тип numeric, длина 4, 2 выделяется для десятичных позиций. Таким образом, в большинстве случаев он будет иметь значение «9,99». VFP принудительно вводит числовое поле максимум до 2 десятичных разрядов, 1 для десятичной запятой, а остальные для целой части числа.

Остальные числовые поля являются числовыми с длиной, но НИКАКИЕ десятичные позиции, которые указывают на то, что они являются целыми числами без десятичной позиции, следовательно, будут рассматриваться как целочисленные типы данных. Числовое значение с десятичной дробью должно идти в виде числа с плавающей запятой или двойного столбца.

При этом, я не знаю, КАК вы даже получаете значение 10,0 в числовом формате 4, 2. Это ПЕРВЫЙ раз, когда я когда-либо видел, чтобы число, превышающее назначенное намерение сохраняемой структуры, фактически сохранялось в поле, подобном этому.

0 голосов
/ 25 ноября 2010

Я не знаю, есть ли у вас доступ к Visual Foxpro, но у него есть «мастер», позволяющий загружать файлы прямо на SQL Server.

Это похоже на бесплатную пробную загрузку в MS через Загрузите Visual Foxpro 9, SP2

. Возможно, проблема связана со столбцами типа memo / blob, которые неправильно интерпретируются.

...