понедельник, 5 августа 2013 г.

Подключение и работа с БД oracle из Visual Studio

    На этот раз моя задача состояла в том, чтобы написать программу, которая могла бы по запросу извлекать вектор-состояния из базы данных Oracle.
    Скажу сразу, у нас такая задача уже была, но настроена она была под 8-й и 10-й oracle клиенты, и работала с другой базой данных по другой технологии.
    Итак, задача: необходимо получить данные с сервера, на котором установлена СУБД Oracle(версию, честно сказать, не узнавал), используя версию клиента 10 и более, а затем произвести с ними некоторые манипуляции.
    Казалось бы, нет ничего проще, подключаемся к БД, пишем запрос и получаем результат. Однако на практике все может оказаться сложнее. Так как Oracle в отличие от SQL Server автоматически не интегрируется с Visual Studio,придется это делать вручную.
Как обычно решений у этой задачи несколько, но начало у всех одинаково - необходимо установить клиент oracle, благо клиент 10-й версии у меня уже был, и настроить в нем доступ к базе данных. Для этого необходимо найти файл с названием «C:\...\oracle\product\10.2.0\client_1\Network\Admin\tnsnames.ora». И заполнить его согласно образцу:
DEBRIS =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.?.???)(PORT = ???))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = debris)
    )
  )

Тут debris – это имя БД. После этого начинаются различия.
Способ первый:
  • необходимо открыть ODBC Administrator и создать там аналогичную запись для драйвера Microsoft ODBC for ORACLE
  • затем в Visual Studio необходимо добавит базу данных, при этом указать поставщика Microsoft ODBC и его настройки; 
  • в настройках поставщика можно проверить подключение
  • далее пишем код получения данных
using System.Data.Odbc;
public void GetData(Action"<"DataItems Exception">" callback)
        {
            DataItems item = null;
            Exception exc = null;
            var dtable = new DataTable();
            const string conectionString = @"Dsn=debris;uid=oper;pwd=oper;server=debris";
            const string queryString = @"SELECT * FROM STAR.VEC_CAT WHERE (ID_KO = 23024) 
                                        ORDER BY DWRD DESC";
            try
            {
                using (var ocon = new OdbcConnection(conectionString))
                {
                    var orcCommand = new OdbcCommand(queryString);
                    ocon.Open();
                    dtable.Load(orcCommand.ExecuteReader());
                    if (dtable.DefaultView != null) item = new DataItems(dtable.DefaultView);
                }
            }
            catch (Exception ex)
            {
                exc = new Exception(ex.Message);
            }
            finally
            {
                callback(item, exc, conectionString);
            }  
  • пример работы функции:
public MainViewModel(IDataService dataService)
        {
            _dataService = dataService;
            _dataService.GetData(
                (items, error) =>
                {
                    if (error != null)
                    {
                        Error = error.Message;
                        return;
                    }
                    DataBaseView = items.DbData;
                });
        }
Такой способ использовался при получении информации из БД в более ранних проектах, однако из-за другой версии oracle на сервере это решение вело себя неустойчиво.
Способ второй:
  •  необходимо открыть ODBC Administrator и создать там запись для клиента Oracle;

  •  в Visual Studio выбрать соответствующего поставщика;

  •  для получения данных использовать следующий код:
using System.Data.OracleClient;
public void GetData(Action"<"DataItems, Exception">" callback)
        {
            DataItems item = null;
            Exception exc = null;
            var dtable = new DataTable();
            const string conectionString = @"DATA SOURCE=DEBRIS;PERSIST SECURITY INFO=True;
                                             USER ID=OPER;PASSWORD=oper";
            const string queryString = @"SELECT * FROM STAR.VEC_CAT WHERE (ID_KO = 23024)
                                                   ORDER BY DWRD DESC";
            try
            {
                using (var ocon = new OracleConnection(conectionString))
                {
                    var orcCommand = new OracleCommand(queryString, ocon);
                    ocon.Open();
                    dtable.Load(orcCommand.ExecuteReader());
                    if (dtable.DefaultView != null) item = new DataItems(dtable.DefaultView);
                }
            }
            catch (Exception ex)
            {
                exc = new Exception(ex.Message);
            }
            finally
            {
                callback(item, exc);
            }           
}
Этот вариант оказался вполне приемлемым, все запросы отрабатывались корректно, однако в Microsoft, к моему сожалению, обозвали этот подход deprecated , и посоветовали использовать Oracle Developer Tolls for Visual Studio.
Способ третий (конечный):
  • в ODBC Administrator ничего делать не надо;
  • скачиваем Oracle Developer Tolls for Visual Studio (ODT);
  • устанавливаем это все согласно мануалу;
  • соединяемся с базой данных через ODP.NET
Вроде бы все в теории просто, однако на практике есть некоторые особенности: вместе с ODT ставится клиент oracle, от установки которого невозможно отказаться (ну или можно, если клиент у вас той же версии, но я это не проверял), на Visual Studio 2012 ставился 11-й клиент oracle и ни грамма меньше.
После всей установки дополнительного софта, для доступа к БД не нужно ничего менять из предыдущего кода:

using Oracle.DataAccess.Client;
public void GetData(Action"<"DataItems, Exception">" callback)
        {
            DataItems item = null;
            Exception exc = null;
            var dtable = new DataTable();
            const string conectionString = @"DATA SOURCE=DEBRIS;PERSIST SECURITY INFO=True;
                                             USER ID=OPER;PASSWORD=oper";
            const string queryString = @"SELECT * FROM STAR.VEC_CAT WHERE (ID_KO = 23024) 
                                         ORDER BY DWRD DESC";
            try
            {
                using (var ocon = new OracleConnection(conectionString))
                {
                    var orcCommand = new OracleCommand(queryString, ocon);
                    ocon.Open();
                    dtable.Load(orcCommand.ExecuteReader());
                    if (dtable.DefaultView != null) item = new DataItems(dtable.DefaultView);
                }
            }
            catch (Exception ex)
            {
                exc = new Exception(ex.Message);
            }
            finally
            {
                callback(item, exc);
            }           
}

кроме первой строки. И еще необходимо скопировать библиотеку Oracle.Data.dll из папки odp.net клиента Oracle в папку bin своего проекта. Это безусловно является большим плюсом. Но вот неожиданностью для меня стало то, что все мои предыдущие программы, которые так или иначе взаимодействовали с БД Oracle, перестали работать. Проблема оказалась в том, что oracle клиент не поддерживал русский язык, но проблема эта решается прописыванием в реестре переменной NLS_LANG (т.е. эту переменную из 10-го клиента необходимо прописать в 11-м).
После этих манипуляций все замечательно заработало. Следует отметить, что для настройки работы SQL Server-а времени у меня ушло намного меньше.

3 комментария:

  1. Большое спасибо, воспользовался описанной Вами схемой - все работает!

    ОтветитьУдалить
  2. А у меня почему-то после установки ODT Visual Studio никак не видит Oracle.DataAccess.Client, и в папке bin нашла только
    Oracle.DataAccess.dll
    Oracle.DataAccess.Resources.dll
    Oracle.Database.Extensions.dll

    ОтветитьУдалить