正在做数据库备份与还原。
我用odp.net通过存储过程+OracleDataAdapter,将数据表直接返回到dataset中,但提示“指定的转换无效”。我就纳闷了,为什么报表应用及查询时,不报这个错,而导出物理表,就报这个错呢。
查资料得知原因:
the OracleDataAdapter class attempts to map Oracle native data types to .NET data types
NUMBER, DATE , TIMESTAMP , TIMESTAMP WITH LOCAL TIME ZONE ,TIMESTAMP WITH TIME ZONE , INTERVAL DAY TO SECOND
上面几种类型可能由于数据库精度和.net的精度 不同,引起异常。比如数据库number是38位,但Decemal只是28位。
Oracle decided that the best way to store these types of data in a Dataset object without losing any detail would be either as a byte array or a string
oracel建议用户 manually define this mapping!
_myAdapter.SafeMapping.Add("LaunchDate", typeof(string)); _myAdapter.SafeMapping.Add("ExpiryDate", typeof(byte[]));
那这么多表,我怎么知道哪个列的精度不对呢?我所有的数据都是number类型。于是写了段代码,
用OracleDataReader循环读列,找出问题列!
OracleDataReader reader = cmd.ExecuteReader(); int x = 0; do { Trace.WriteLine("表" + (++x)); while (reader.Read()) { string result = reader.GetString(3) + "-" + reader.GetString(4) + "+"; for (int j = 6; j < reader.FieldCount - 1; j++) { try { if (!reader.IsDBNull(j) && reader.GetFieldType(j)==typeof( decimal)) result += (reader.GetDecimal(j).ToString() + ","); else result += ("null,"); } catch (Exception ex) { Trace.WriteLine("wrong filed "+j+" "+result); conn.Close(); throw; } } Trace.WriteLine(result); } } while (reader.NextResult());
终于找到了 问题列!
其实用到几处OracleDataReader 的知识点
reader.Read() reader.IsDBNull(j) reader.GetFieldType(j) reader.NextResult()
NextResult就是在多个结果集间循环。因为我过程一次性返回了20个游标集。
大家看,用OracleDataReader就是如此复杂,但我已经找到了问题列,从库里把数据修改成精度以内之后。就可以这样:
OracleDataAdapter oda = new OracleDataAdapter(cmd);
oda.Fill(ds);
就两句话,一次性把所有的表统统转存到了dataset中去。不要太爽好不好