Mybatis.NET Oracle 線上神奇問題:Value does not fall within the expected range.


1、錯誤現象

 

  在向數據庫查詢一條數據的時候報如下錯誤:

1    Value does not fall within the expected range.
2    at Oracle.ManagedDataAccess.Client.OracleParameter.set_Value(Object value)
3    at MyBatis.DataMapper.Data.DefaultPreparedCommand.ApplyParameterMap(IDbProvider dbProvider, IDbCommand command, RequestScope request, IStatement statement, Object parameterObject)
4    at MyBatis.DataMapper.Data.DefaultPreparedCommand.Create(RequestScope request, ISession session, IStatement statement, Object parameterObject)
5    at MyBatis.DataMapper.MappedStatements.MappedStatement.Execute[T](Object preEvent, Object postEvent, ISession session, Object parameterObject, Func`3 requestRunner)
6    at MyBatis.DataMapper.MappedStatements.MappedStatement.ExecuteInsert(ISession session, Object parameterObject)
7    at MyBatis.DataMapper.DataMapper.Insert(String statementId, Object parameterObject)

 錯誤信息也很簡單。在向OracleParameter的屬性Value賦值時報錯。

 

2、找不出的錯誤原因

  源碼如下:

  

 1 [Category("Data"), Description(""), DefaultValue((string) null)]
 2 public override object Value
 3 {
 4     get => 
 5         this.m_value;
 6     set
 7     {
 8         if (((value != null) && (value != DBNull.Value)) && (this.m_enumType == PrmEnumType.NOTSET))
 9         {
10             Type type = value.GetType();
11             if (((type == typeof(sbyte)) || (type == typeof(ushort))) || ((type == typeof(uint)) || (type == typeof(ulong))))
12             {
13                 throw new ArgumentException();
14             }
15             object obj2 = OraDb_DbTypeTable.s_table[type];
16             if ((obj2 == null) && type.IsArray)
17             {
18                 obj2 = OraDb_DbTypeTable.s_table[type.GetElementType()];
19             }
20             if (obj2 == null)
21             {
22                 throw new ArgumentException();
23             }
24             this.m_oraDbType = (OracleDbType) obj2;
25             this.m_bSetDbType = false;
26             this.m_enumType = PrmEnumType.VALUE;
27         }
28         this.m_value = value;
29     }
30 }
31  

  從源碼可以看到,報錯可能出現在兩個地方:if (((type == typeof(sbyte)) || (type == typeof(ushort))) || ((type == typeof(uint)) || (type == typeof(ulong))))【更老的驅動版本bool類型也不支持】 和 if (obj2 == null)。出現這個錯誤說明無法將C#類型映射為Oracle類型。

  首先檢查第一處可能,發現插入報錯的類中使用的類型有DateTime,DateTime?,long,int,string。發現第一處不滿足。

  檢查第二次可能,第二處取類型是從 OraDb_DbTypeTable 獲取到的。源碼如下:

  

 1 internal static void InsertTableEntries()
 2 {
 3     s_table.Add(typeof(byte), OracleDbType.Byte);
 4     s_table.Add(typeof(byte[]), OracleDbType.Raw);
 5     s_table.Add(typeof(char), OracleDbType.Varchar2);
 6     s_table.Add(typeof(char[]), OracleDbType.Varchar2);
 7     s_table.Add(typeof(DateTime), OracleDbType.TimeStamp);
 8     s_table.Add(typeof(short), OracleDbType.Int16);
 9     s_table.Add(typeof(int), OracleDbType.Int32);
10     s_table.Add(typeof(long), OracleDbType.Int64);
11     s_table.Add(typeof(float), OracleDbType.Single);
12     s_table.Add(typeof(double), OracleDbType.Double);
13     s_table.Add(typeof(decimal), OracleDbType.Decimal);
14     s_table.Add(typeof(string), OracleDbType.Varchar2);
15     s_table.Add(typeof(TimeSpan), OracleDbType.IntervalDS);
16     s_table.Add(typeof(OracleBFile), OracleDbType.BFile);
17     s_table.Add(typeof(OracleBinary), OracleDbType.Raw);
18     s_table.Add(typeof(OracleBlob), OracleDbType.Blob);
19     s_table.Add(typeof(OracleClob), OracleDbType.Clob);
20     s_table.Add(typeof(OracleDate), OracleDbType.Date);
21     s_table.Add(typeof(OracleDecimal), OracleDbType.Decimal);
22     s_table.Add(typeof(OracleIntervalDS), OracleDbType.IntervalDS);
23     s_table.Add(typeof(OracleIntervalYM), OracleDbType.IntervalYM);
24     s_table.Add(typeof(OracleRefCursor), OracleDbType.RefCursor);
25     s_table.Add(typeof(OracleString), OracleDbType.Varchar2);
26     s_table.Add(typeof(OracleTimeStamp), OracleDbType.TimeStamp);
27     s_table.Add(typeof(OracleTimeStampLTZ), OracleDbType.TimeStampLTZ);
28     s_table.Add(typeof(OracleTimeStampTZ), OracleDbType.TimeStampTZ);
29     s_table.Add(typeof(OracleXmlType), OracleDbType.XmlType);
30     s_table.Add(typeof(bool), OracleDbType.Boolean);
31     s_table.Add(typeof(DateTimeOffset), OracleDbType.TimeStampTZ);
32 }

  發現里面沒有DateTime?,難道是這個地方不行。那也不對啊,其它地方同樣類型是可以保存到數據庫的啊。繼續找下去在 MyBatis.DataMapper.Data.DefaultPreparedCommand.ApplyParameterMap 找到了信息。源碼如下:

  

 1 public virtual void SetParameter(IDataParameter dataParameter, object parameterValue, string dbType)
 2 {
 3     if (parameterValue != null)
 4     {
 5         dataParameter.Value = parameterValue;
 6     }
 7     else
 8     {
 9         dataParameter.Value = DBNull.Value;
10     }
11 }

  如果值為null,會自動賦值為 DBNull.Value 也就會不會報錯。既然都不會出現問題,可問題又會出現在哪里呢?

 

3、柳暗花明

  在本地嘗試各種方法后仍然不能重現,只能讓領導將生產程序包拷貝一份下來進行嘗試。

  包拿到之后,進行必要配置啟動,出現了新的詭異問題 Redis報錯 :No connection is available to service this operation。仔細檢查Redis配置發現問題。抓下內存快照看看實際配置信息是什么:

  

 

   看到這個一臉懵逼,Password竟然是null,明明已經配置了啊。查看了加載配置的源碼,發現根本不會解析Password配置,還有這種操作,這程序包是有多老。弄好了Redis,啟動保存數據,果然不行。反編譯生產源碼,發現驚天一幕:

  

 

   Id的類型竟然ulong。我擦這是多久沒有更新了。原因至此是找到了。

 

4、吐槽

 

  這個服務是公司內部自己用的,很古老了。以前都是手工拷貝程序包發布的。最近由於公司發生了些意外事情,原來服務器不能用,需要部署新的服務器上。由於古老,不知道老大當時拿了多么古老的程序包部署了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM