2015-12-02 38 views
0

我正在尝试将我为SQL Server连接编写的代码进行转换以使用Odbc数据源。我已经遇到了OdbcDataReader.GetValue(int)尝试为字符串字段调用OdbcDataReader.internalGetDate的问题。Odbc使用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) 

我评论了参考源here这表明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使用internalGetDate尝试被报道这是一个CHAR但随后并解析数据?我错过了明显的东西吗?

Even weirder是当我在该索引上调用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) 
+0

问题..你通过ODBC访问什么类型的数据库..?是这个Sql Server ..?如果是这样,那么为什么不远离'System.Data.Odbc'对象并使用SqlClient数据对象。 – MethodMan

回答

0

这个问题实际上是涉及到数据库服务器(在这种情况下,4D)涉及空日期为00/00/0000 12:00:00 AM另一个问题。这个日期不能被DateTime解析,因此OdbcDataReader崩溃。我通过捕获异常并将我的类的属性设置为null来解决了第一个问题,但这并没有解决潜在的问题。 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; 
}