首页 文章

如何强制ADO.Net仅在reader TableSchema中使用System.String DataType

提问于
浏览
11

我正在使用OleDbConnection来查询Excel 2007电子表格 . 我想强制OleDbDataReader只使用字符串作为列数据类型 .

系统正在查看前8行数据并将数据类型推断为Double . 问题是在第9行我在该列中有一个字符串,OleDbDataReader返回一个Null值,因为它无法转换为Double .

我使用过这些连接字符串:

Provider = Microsoft.ACE.OLEDB.12.0; Data Source =“ExcelFile.xlsx”; Persist Security Info = False; Extended Properties =“Excel 12.0; IMEX = 1; HDR = No”Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source =“ExcelFile.xlsx”; Persist Security Info = False; Extended Properties =“Excel 8.0; HDR = No; IMEX = 1”

看看reader.GetSchemaTable() . Rows [7] .ItemArray [5],它的dataType是Double .

此架构中的第7行与我遇到问题的Excel中的特定列相关联 . ItemArray [5]是它的DataType列

Is it possible to create a custom TableSchema for the reader so when accessing the ExcelFiles, I can treat all cells as text instead of letting the system attempt to infer the datatype?


我在这个页面找到了一些很好的信息:Tips for reading Excel spreadsheets using ADO.NET

关于ADO.NET接口的主要特点是如何处理数据类型 . (您会注意到我在阅读电子表格时一直在仔细避免返回哪些数据类型的问题 . )您准备好了吗? ADO.NET扫描前8行数据,并基于此猜测每列的数据类型 . 然后它会尝试将该列中的所有数据强制转换为该数据类型,并在强制失败时返回NULL!

谢谢,
基思


这是我的代码的简化版本:

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

  • 0

    正如您所发现的那样,OLEDB使用的是Jet,它的调整方式有限 . 如果您设置使用OleDbConnection从Excel文件中读取,则需要将 HKLM\...\Microsoft\Jet\4.0\Engines\Excel\TypeGuessRows 值设置为零,以便系统扫描整个结果集 .

    也就是说,如果您愿意使用替代引擎从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();
        }
    }
    
  • 1

    查看this page的最终答案 .


    刚注意到你提到的页面说的是同样的事情......


    Update

    问题似乎是JET引擎本身而不是ADO . 一旦JET决定了类型,它就会坚持下去 . 之后做的任何事都没有效果;比如将值转换为SQL中的字符串(例如Cstr([Column]))只会导致返回一个空字符串 .

    此时(如果没有其他答案)我会选择其他方法:修改电子表格;修改注册表(不理想,因为你将搞乱使用JET的每个其他应用程序的设置); Excel自动化或不使用JET的第三方组件 .

    如果自动化选项要慢,那么可以使用它以不同的格式保存电子表格,这样更容易处理 .

  • 1

    注意64位操作系统它在这里:

    My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel
    
  • 7

    我遇到了同样的问题,并确定这是许多人经常遇到的事情 . 以下是一些已经提出的解决方案,其中许多已尝试实施:


    • 将以下内容添加到连接字符串(Source):

    TypeGuessRows = 0; ImportMixedTypes = Text

    IMEX = 1; HDR = NO;

    Hkey_Local_Machine / Software / Microsoft / Jet / 4.0 / Engines / Excel / TypeGuessRows Hkey_Local_Machine / Software / Microsoft / Jet / 4.0 / Engines / Excel / ImportMixedTypes

    • 考虑使用替代库来读取excel文件:

    • EPPlus

    • ExcelDataReader(也建议是@Thomas)

    • OpenXml

    • 将源文件中的所有数据格式化为Text(至少前8行),但我知道这通常是不切实际的(Source,虽然这与SSIS有关,但它是相同的概念)

    • 使用Schema.ini文件在导入文件之前定义数据类型,我发现这与直接使用"Jet.OleDb"有关,可能要求您修改连接字符串 . 这可能只适用于CSV我没试过这种方法 . (SourceRelated Post


    这些都不适合我(虽然我相信他们已经为之努力其他) . 我对@Asher所表达的观点表示,这个问题确实没有很好的解决方案 . 在我的软件中,我只是向用户显示一条错误消息(如果任何必需的列包含空值),指示它们为format all columns as "Text" .

    老实说,我认为this book更适用于情况 . 已经多次说过的问题是:

    • "The data type at the destination is varchar but the assumed data type of " double " nullifies any data that doesn't fit."(Source

    • "But the problem is actually with the OLEDBDataReader. The problem is that if it sees mostly numbers in a column, it assumes everything is a number - if a row item being read is not a number, it simply sets it to null! Ouch!"(Source

    • “问题似乎与JET引擎本身有关,而不是ADO . 一旦JET决定类型,它就会坚持下去 . ”(@ Asher)

    虽然我很清楚这是一个有意的设计决定,而且只是Jet Database Library的工作方式 . 我毫不犹豫地称这个库完全没用,因为我认为对于很多人来说这些解决方案中的一些确实有效,但到目前为止,我的项目已经得出结论,这个库无法在一列中读取多种数据类型而且不适合用于一般数据检索 .

相关问题