Odbc使用internalGetDate将字符串解析为Date

本文关键字:Date 字符串 使用 internalGetDate Odbc | 更新日期: 2023-09-27 18:25:32

我正在尝试将我为SQL Server连接编写的一些代码转换为使用Odbc数据源。我在尝试为字符串字段调用OdbcDataReader.internalGetDate时遇到了一些问题。

以下是我目前用于获取值的代码:

private static void ReadRecord<T>(IDataRecord record, T myClass)
{
    .... inside loop of datarecord fields ....
        var value = record.GetValue(i);
        pi.SetValue(myClass,
            value == DBNull.Value
                ? null
                : Convert.ChangeType(value, record.GetFieldType(i)), null);

当我使用Odbc对特定的4D数据表执行此操作时,我会得到一个没有附加消息的OdbcException。异常堆栈跟踪显示使用了internalGetDate。

at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)
at System.Data.Odbc.OdbcDataReader.GetData(Int32 i, SQL_C sqlctype, Int32 cb, Int32& cbLengthOrIndicator)
at System.Data.Odbc.OdbcDataReader.GetData(Int32 i, SQL_C sqlctype)
at System.Data.Odbc.OdbcDataReader.internalGetDate(Int32 i)
at System.Data.Odbc.OdbcDataReader.GetValue(Int32 i, TypeMap typemap)
at System.Data.Odbc.OdbcDataReader.GetValue(Int32 i)
at System.Data.Odbc.DbCache.AccessIndex(Int32 i)
at System.Data.Odbc.OdbcDataReader.GetValue(Int32 i)

我查看了这里的参考源,它显示执行GetSqlType是为了确定在稍后的GetValue()调用中要调用的函数。我写这段代码是为了检查有问题的索引的SqlType

var odbcdatareader = typeof(OdbcDataReader);
var method = odbcdatareader.GetMethod("GetSqlType", BindingFlags.Instance | BindingFlags.NonPublic);
var type = method.Invoke(record, new object[] { i });
var typemap = odbcdatareader.Assembly.GetType("System.Data.Odbc.TypeMap");
var typemapodbctype = typemap.GetField("_odbcType", BindingFlags.Instance | BindingFlags.NonPublic);
var typemapdbtype = typemap.GetField("_dbType", BindingFlags.Instance | BindingFlags.NonPublic);
var typemaptype = typemap.GetField("_type", BindingFlags.Instance | BindingFlags.NonPublic);
var typemapsqltype = typemap.GetField("_sql_type", BindingFlags.Instance | BindingFlags.NonPublic);
Console.WriteLine("{0}, {1}, {2}, {3}", typemapodbctype.GetValue(type),
    typemapdbtype.GetValue(type), typemaptype.GetValue(type),
    typemapsqltype.GetValue(type));

此检查的结果为:

Char, AnsiStringFixedLength, System.String, CHAR

为什么Odbc的GetSqlType会将其报告为CHAR,但却使用internalGetDate来尝试解析数据?我是不是错过了一些显而易见的东西?

更奇怪的是,当我对该索引调用GetString()时,我也会得到一个internalGetDate()错误。

at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)
at System.Data.Odbc.OdbcDataReader.GetData(Int32 i, SQL_C sqlctype, Int32 cb, Int32& cbLengthOrIndicator)
at System.Data.Odbc.OdbcDataReader.GetData(Int32 i, SQL_C sqlctype)
at System.Data.Odbc.OdbcDataReader.internalGetDate(Int32 i)
at System.Data.Odbc.OdbcDataReader.GetValue(Int32 i, TypeMap typemap)
at System.Data.Odbc.OdbcDataReader.GetValue(Int32 i)
at System.Data.Odbc.DbCache.AccessIndex(Int32 i)
at System.Data.Odbc.OdbcDataReader.internalGetString(Int32 i)
at System.Data.Odbc.OdbcDataReader.GetString(Int32 i)

Odbc使用internalGetDate将字符串解析为Date

此问题实际上与数据库服务器(在本例中为4D)将空日期关联为00/00/0000 12:00:00 AM的另一个问题有关。DateTime无法解析此日期,因此OdbcDataReader崩溃。我通过捕获异常并将类的属性设置为null来解决第一个问题,但这并没有解决根本问题。由于异常,DbCache没有缓存该值,并且由于OdbcDataReader和DbCache的工作方式,系统必须在每个字段上循环并获取其数据。这就是根本错误。GetString在0..i中循环,并在i-1字段的internalGetDate上崩溃。

这个决议……在我看来相当丑陋,但符合我的目的。

catch (ArgumentOutOfRangeException ex)
{
    if (ex.Message == "Year, Month, and Day parameters describe an un-representable DateTime.")
    {
        pi.SetValue(myClass, null, null);
        var odbcdatareader = typeof(OdbcDataReader);
        var dataCache = odbcdatareader.GetField("dataCache",
            BindingFlags.Instance | BindingFlags.NonPublic);
        var dbcache = dataCache.GetValue(record);
        var valuesfield = dbcache.GetType()
            .GetField("_values", BindingFlags.Instance | BindingFlags.NonPublic);
        var values = (object[]) valuesfield.GetValue(dbcache);
        values[i] = new DateTime(1, 1, 1);
        valuesfield.SetValue(dbcache, values);
    }
    else
        throw;
}