Переход с ODAC 10 на ODAC 12

в 6:33, , рубрики: .net, c#.net, odac, oracle, Oracle.DataAccess, смена версии

Всем доброго утра!

Понадобилось нам тут в оперативном порядке перейди на Oracle.DataAcess 12й версии в нашем .Net проекте. И все нормально шло ровно до того момента, как мы попытались запустить приложение. В паре тысяч мест внезапно вывалилась ошибка типа:

Unable to cast object of type 'Oracle.DataAccess.Types.OracleDecimal' to type 'System.IConvertible'.


Поиск по форумам дал ответ — в 11й версии что-то конкретно переиграли в OracleParameter и как следствие — все Convert.ToXXX в нашем проекте отвалились.
В качестве решения в блоге Mark Williams oradim.blogspot.ru/2009/08/odpnet-vb-and-from-type-to-type-is-not.html предлагается следующее:

If you are having conversion problems in your code with «output» or «return values» keep in mind that setting OracleDbType vs. DbType will determine whether a .NET Framework type or an Oracle provider type is returned. Also, the current ODP.NET Beta (11.1.7.10) exposes a new property for the OracleParameter class: OracleDbTypeEx This property allows you to bind values using the OracleDbType but will return values as .NET types.

Автоматом это свойство не инициализируется. Во внутренностях ODAC через dotPeek был обнаружен следующий кусок:

    public OracleDbType OracleDbType
    {
      get
      {
        return this.m_oraDbType;
      }
      set
      {
        if (this.m_oraDbType != value)
        {
          OracleDbType oracleDbType = value;
          if (oracleDbType < OracleDbType.BFile || oracleDbType > OracleDbType.Boolean)
            throw new ArgumentOutOfRangeException();
          this.m_oraDbType = oracleDbType;
        }
        this.m_bSetDbType = false;
        this.m_enumType = PrmEnumType.ORADBTYPE;
        this.m_bOracleDbTypeExSet = false;
      }
    }

 public OracleDbType OracleDbTypeEx
    {
      get
      {
        return this.m_oraDbType;
      }
      set
      {
        this.OracleDbType = value;
        this.m_bOracleDbTypeExSet = true;
      }
    }

Т.е. нужное свойство из конструктора параметра само не инициализируется, нужно явно добавлять его простановку в код, чтобы поле this.m_bOracleDbTypeExSet перешло в true.
Перепиливать огромное количество объявлений команд нам решительно не хотелось, благо у нас уже была своя библиотечка с методами-расширителями для OracleCommand и мы дописали еще метод:

public static int ExecuteNonQueryExt(this OracleCommand cmd)
        {
            foreach (OracleParameter param in cmd.Parameters)
            {
                param.OracleDbTypeEx = param.OracleDbType;
            }
            return cmd.ExecuteNonQuery();
        }

А дальше автозаменой по проекту ExecuteNonQuery на ExecuteNonQueryExt и бинго! Все завелось и полетело. :-)
Возможно и есть какой-то более безболезненный способ выполнить этот переход, не переписывая половину проекта, но на форумах решение найти не получилось. Хотя грабли довольно старые и многие наступили на них еще в момент выхода 11й версии.

Автор: sKs

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js