Как заставить ADO.Net использовать только систему.Строковый тип данных в TableSchema читателей

Я использую OleDbConnection для запроса электронной таблицы Excel 2007. Я хочу заставить OleDbDataReader использовать только строку в качестве типа данных столбца.

система смотрит на первые 8 строк данных и делает вывод, что тип данных должен быть двойным. Проблема в том, что в строке 9 у меня есть строка в этом столбце, и OleDbDataReader возвращает значение Null, так как оно не может быть приведено к Double.

я использовал эти строки подключения:

Поставщик=Microsoft.ТУЗ.Oledb для.12.0;Источник Данных="ExcelFile.xlsx"; Persist Security Info=False;расширенные свойства= "Excel 12.0; IMEX=1; HDR=No"

Поставщик=Microsoft.Реактивный.Oledb для.4.0;Источник Данных="ExcelFile.xlsx"; Persist Security Info=False;расширенные свойства= "Excel 8.0; HDR=нет; IMEX=1"

глядя на читателя.Getschematable в().Строк[7].ItemArray[5], это тип данных двойной.

строка 7 в этой схеме коррелирует с конкретный столбец в Excel у меня возникли проблемы. ItemArray[5] - это столбец типа данных

можно ли создать пользовательскую TableSchema для читателя, чтобы при доступе к ExcelFiles я мог обрабатывать все ячейки как текст, а не позволять системе пытаться вывести тип данных?


Я нашел хорошую информацию на эту страницу: советы по чтению электронных таблиц Excel с помощью ADO.NET

главная причуда о ADO.NET интерфейс-это способ обработки типов данных. (Вы заметите, что я тщательно избегал вопроса о том, какие типы данных возвращаются при чтении электронной таблицы. Вы готовы к этому? ADO.NET сканирует первые 8 строк данных и на основе этого угадывает тип данных для каждого столбца. Затем он пытается принудить все данные из этого столбца к этому типу данных, возвращая NULL всякий раз, когда принуждение терпит неудачу!

спасибо ты,
Кит!--2-->


вот уменьшенная версия моего кода:

using (OleDbConnection connection = new OleDbConnection(BuildConnectionString(dataMapper).ToString()))
{
    connection.Open();
    using (OleDbCommand cmd = new OleDbCommand())
    {
        cmd.Connection = connection;
        cmd.CommandText = SELECT * from [Sheet1$];
        using (OleDbDataReader reader = cmd.ExecuteReader())
        {
            using (DataTable dataTable = new DataTable("TestTable"))
            {
                dataTable.Load(reader);
                base.SourceDataSet.Tables.Add(dataTable);
            }
        }
    }
}

4 ответов


как вы обнаружили, OLEDB использует Jet, который ограничен способом, которым его можно настроить. Если вы настроены на использование OleDbConnection для чтения из файла Excel, то вам нужно установить HKLM\...\Microsoft\Jet.0\Engines\Excel\TypeGuessRows значение равно нулю, так что система будет сканировать весь resultset.

тем не менее, если вы открыты для использования альтернативного движка для чтения из файла Excel, вы можете попробовать ExcelDataReader. Он читает все столбцы как строки, но позволит вам использовать объект DataReader.Getxxx методы для получения типизированных значений. Вот образец, который заполняет DataSet:

DataSet result;
const string path = @"....\Test.xlsx";
using ( var fileStream = new FileStream( path, FileMode.Open, FileAccess.Read ) )
{
    using ( var excelReader = ExcelReaderFactory.CreateOpenXmlReader( fileStream ) )
    {
        excelReader.IsFirstRowAsColumnNames = true;
        result = excelReader.AsDataSet();
    }
}

Проверьте окончательный ответ на на этой странице.


просто заметил, что страница, на которую вы ссылаетесь, говорит то же самое ...


обновление:

проблема, похоже, в самом реактивном двигателе, а не в ADO. Как только JET решает тип, он прилипает к нему. Все, что сделано после этого, не имеет никакого эффекта; например, приведение значений в строку в SQL (например, Cstr ([Column])) просто приводит к пустой строке возвращенный.

на данный момент (если нет других ответов) я бы выбрал другие методы: изменение электронной таблицы; изменение реестра (не идеально, так как вы будете возиться с настройками для каждого другого приложения, которое использует JET); автоматизация Excel или компонент третьей стороны, который не использует JET.

Если опция автоматизации должна замедляться, возможно, просто используйте ее для сохранения электронной таблицы в другом формате, который легче обрабатывать.


Примечание Для 64-битной ОС здесь:

My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet.0\Engines\Excel

Я столкнулся с той же проблемой и определил, что это то, что многие люди обычно испытывают. Вот несколько решений, которые были предложены, многие из которых я пытался реализовать:


  1. добавьте в строку подключения (источник):

TypeGuessRows=0; ImportMixedTypes=Text

  1. добавьте в строку подключения (источник, Обсуждение, Еще Больше):

IMEX=1; HDR=НЕТ;

  1. измените следующие параметры реестра, отключите "TypeGuessRows " и" ImportMixedTypes "установите значение "Text" (источник, Не Рекомендуется, Больше Документации):

Hkey_Local_Machine / Программное Обеспечение / Microsoft / Jet / 4.0 / Двигатели / Excel/TypeGuessRows Hkey_Local_Machine/Программное Обеспечение/Microsoft/Jet/4.0/Двигатели/Excel / ImportMixedTypes

  1. рассмотрите возможность использования альтернативной библиотеки для чтения файла excel:

  2. форматировать все данные в исходном файле в виде текста(по крайней мере, первые 8 строк), хотя я понимаю это обычно непрактично (источник, хотя это отношение к SSIS, но это те же понятия)

  3. использовать схему.ini-файл чтобы определить тип данных перед импортом файла, я нашел это в отношении использования " Jet.OleDb " напрямую, возможно, требуя от вас изменения строки подключения. Это может быть применимо только к CSV, я не пробовал этот подход.(источник, обзоры Пост)


ни одна из них не работал для меня(хотя я считаю, что они работали для других). Я придерживаюсь мнения, выраженного @Asher, что на самом деле нет хорошего решения этой проблемы. В моем программном обеспечении я просто отображаю сообщение об ошибке Пользователю (если любой требуемый столбец содержит пустые значения), указывая им отформатировать все столбцы, как "текст".

честно говоря, я думаю книги более применимо к ситуации. Вопрос, уже заявленный несколько раз:

  • " тип данных в пункте назначения-varchar, но предполагаемые данные тип "double" аннулирует любые данные, которые не подходят."(источник)

  • " но проблема на самом деле с OLEDBDataReader. Проблема если он видит в основном числа в столбце, он предполагает все является числом - если считываемый элемент строки не является числом, он просто устанавливает значение null! Оуч!"(источник)

  • "проблема, похоже, в самом реактивном двигателе, а не в ADO. Однажды JET решает тип, он прилипает к нему."(@Asher)

хотя я не нашел ничего из этого документированного в официальном качестве, я думаю, что очень ясно, что это преднамеренное дизайнерское решение и просто как Библиотека Базы Данных Jet строительство. Я не решаюсь назвать эту библиотеку совершенно бесполезной, потому что думаю: многих людей некоторые из этих решений работают, но до сих пор для моего проекта, Я пришел к выводу, что эта библиотека не удается прочитать несколько типов данных в одном столбце и плохо подходит для получения общих данных.