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)
此问题实际上与数据库服务器(在本例中为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;
}