Введение
Одной из важнейших возможностей постреляционной системы управления базами данных Caché является предоставление объектного подхода к описанию и обработке хранимых данных. Используя множественное наследование, полиморфизм и сложные типы данных, разработчики могут моделировать предметную область, используя все основные идеи объектной архитектуры и современные технологии объектного моделирования, ускоряя таким образом, процесс разработки приложений. Но Caché идет дальше и предлагает возможность использования гибкого и мощного объектного подхода не только на уровне серверной логики, но и при создании клиентских приложений. В результате разработчики даже выйдя за пределы Caché продолжают использовать те же термины и понятия, оперируя теми же сущностями, что и в рамках серверных методов. Спектр возможностей по использованию объектов Caché в клиентских приложениях невероятно широк. Это "родное" проецирование классов Caché в классы Java, C++ и .Net, использование ActiveX для взаимодействия с объектами Caché из Windows-приложений, наконец системные классы для работы с объектами Caché из Perl и Python. Некоторые из этих способов взаимодействия являются предметом настоящей статьи.
.Net Managed Provider
Caché Managed Provider для .Net обеспечивает простой и эффективный способ работать с Caché из .Net-приложений. Это уникальный компонент, который одновременно обеспечивает и реляционный, и объектный доступ к данным, используя общий программный интерфейс. Caché Managed Provider обеспечивает:
- Реляционный доступ к данным, используя ADO.NET API.
- Высокопроизводительный и удобный объектный доступ к данным через автоматически генерируемые промежуточные классы. Эти промежуточные классы соответствуют классам Caché и обеспечивают хранение объектов, извлечение и кэширование данных, а так же управление жизненным циклом объектов.
- Простоту развертывания в среде .Net за счет того, что Caché Managed Provider реализован как управляемый .Net-код
- Возможность использования Caché Managed Provider для .Net в многопоточных (multi-threaded) .Net-приложениях.
Caché предоставляет стандартный набор классов Connection, Command, CommandBuilder, DataReader, и DataAdapter, а также специальные расширения библиотеки классов, предоставляющие разработчикам выходящие за рамки общепринятых возможности.
Рис. 1. Общий подход к созданию .Net приложений в Caché
Одна из исключительных особенностей Caché - предоставление за счет этих расширений объектного способа доступа к данным, дополнительно к представлению данных в виде строк реляционных таблиц. Как результат, в .Net приложении используются ровно те же классы, что использовались при написании серверной логики в Caché. Это позволяет работать со сложными пользовательским типами данных, анализировать связи и отношения между объектами, работать со списками, массивами и потоками данных, применяя те же техники, что и в рамках серверной логики на Caché. Простейший пример работы с объектами Caché в .Net приложении приведен в листинге 1. В этом примере создается локальное соединение с сервером Caché, который работает на 1972 порту, с областью SAMPLES, содержащей типовые примеры, поставляемые с СУБД Caché. В этой области открывается объект класса Sample.Person с идентификатором равным 1 и выводится в консоль значение свойства Name и код возврата метода Id().
CacheConnection CacheConnect = new CacheConnection();
CacheConnect.ConnectionString = "Server = localhost; "
+ "Port = 1972; " + "Namespace = SAMPLES; "
+ "Password = sys; " + "User ID = _system;";
CacheConnect.Open();
Sample.Person person = Sample.Person.OpenId(CacheConnect, "1");
Console.WriteLine("Свойства: \r\n "
+ person.Id() +
+ person.Name
);
person.Close();
CacheConnect.Close();
Очевидно, что полностью аналогичный код можно реализовать, используя реляционный способ работы с данными. В этом примере те же самые действия выполняются уже в реляционных терминах, опираясь на то, что Caché автоматически создает необходимые описания реляционных таблиц для каждого хранимого класса. При этом в общем случае одному классу может соответствовать несколько таблиц, поскольку объектный подход мощнее, чем реляционный. Примером может стать наличие у класса свойства-массива строк, при наличии которого соответствующий класс проецируется в две реляционные таблицы.
CacheConnection CacheConnect = new CacheConnection();
CacheConnect.ConnectionString = "Server = localhost; "
+ "Port = 1972; " + "Namespace = SAMPLES; "
+ "Password = sys; " + "User ID = _system;";
CacheConnect.Open();
string SQLtext = "SELECT * FROM Sample.Person WHERE ID = 1";
CacheCommand Command = new CacheCommand(SQLtext, CacheConnect);
CacheDataReader Reader = Command.ExecuteReader();
while (Reader.Read()) {
Console.WriteLine("Свойства: \r\n "
+ Reader[Reader.GetOrdinal("ID")] +
+ Reader[Reader.GetOrdinal("Name")]);
};
Reader.Close();
Command.Dispose();
CacheConnect.Close();
Очевидно, что работа в терминах объектов имеет ряд существенных преимуществ перед работой в терминах SQL:
- Простота. Исходный код значительно более понятен и дальнейшая его модернизация и модификация происходит значительно легче, по сравнению с аналогичным кодом, использующим SQL для работы с данными, что в конечном итоге сказывается на сроках разработки и конечной стоимости решения
- Использование сложных структур. Объектный подход, предоставляемый Caché позволяет работать со сложными типами данных, встраиваемыми классами, различными типами отношений между классами, коллекциями литералов и ссылок на объекты. Все эти компоненты доступны при помощи Caché Managed Provider.
С другой стороны, применение реляционного подхода позволяет использовать стандартные визуальные компоненты, такие как списки, таблицы и др. Как результат, Caché .Net Managed Provider предоставляет уникальные возможности по созданию .Net приложений с использованием всех преимуществ объектного подхода к обработке данных, хранящихся в БД Caché, в сочетании со стандартным реляционным подходом к работе с теми же данными.
C++ и Java Binding
Интерфейсы C++ и Java Binding, или объектная связка Caché с C++ и Java, - это очень схожие технологии, основной идеей которых является проецирование классов Caché в соответствующие классы Java и C++. Рассмотрим технологию подробнее в терминах С++. Для Java концепция точно такая же, с точностью то синтаксиса, детали можно изучить, используя документацию Caché.
Интерфейс Caché C++ Binding позволяет представить и использовать классы Caché как родные (Native) классы C++. Интерфейс включает в себя следующие основные модули:
- Генератор классов Caché;
- Библиотека Caché С++;
- Специальный процесс (сервер) Caché.
Работа с классами Caché из среды C++ осуществляется через прокси-классы, которые создаются генератором классов Caché и включаются в С++ проект директивой #include.
Библиотека Caché C++ содержит ряд классов-проекций системных классов Caché и используется при генерации пользовательских классов-проекций и для реализации пользовательской логики, работающей непосредственно с системными классами Caché (например, работа со списками, массивами, обработка запросов и др.).
Все взаимодействие между сервером Caché и прокси-классами С++ обслуживается специальным процессом Caché. При этом, любое обращение к серверу Caché со стороны клиентского приложения, в частности, выполнение функции-члена С++ класса-проекции, отслеживается и обрабатывается данным процессом. Этот же процесс осуществляет связку с Java-приложением.
Рис. 2. Архитектура Caché С++ Binding
В текущей версии Caché 5.1.829. поддерживается интерфейс C++ Binding для Microsoft VS 6.0, 7.1 и Borland C++ Builder. В коде программы на С++ используются классы-проекции Caché, как родные классы С++. При этом проецированные классы содержат все методы, реализованные в Caché и повторяют иерархию наследования классов. Рассмотрим пример работы с классом Caché из программы на С++.
//Осуществляем соединение с Caché и областью Samples, используя имя пользователя _SYSTEM и пароль SYS
d_connection conn = tcp_conn::connect("localhost[1972]:Samples",
"_SYSTEM", "SYS", &conn_err);
Database db(conn);
//Открываем объект класса-проекции с ID=1
d_ref<Sample_Person> obj = Sample_Person::openid(&db,L"1");
//Выводим значение свойства Name открытого объекта
std::cout << obj->getName();
//Выводим код возврата метода %Id()
std::cout << obj->sys_Id() << '\n';
Точно таким же образом происходит работа со списками, массивами, потоками, отношениями между классами и другими элементами объектной модели Caché. Также можно использовать системные классы Caché, например, класс %ResultSet для выполнения SQL запросов к БД.
d_query query(&db);
d_string name;
d_int id;
const wchar_t* sql_query = L"select ID, Name from Sample_Person where ID= ?";
int size = wcslen(sql_query);
query.prepare(sql_query, size);
query.set_par(1, "1");
query.execute();
while (query.fetch()){
query.get_data(&id);
query.get_data(&name);
std::cout << id << std::string(name) << "\n";
}
Object Factory
Для работы из ActiveX-совместимых сред разработки можно использовать очень интересный компонент Caché Object Factory. Это ActiveX-компонент, который позволяет создавать объекты различных классов Caché в клиентском приложении, именно поэтому он называется объектной фабрикой. Этот интерфейс не требует предварительного импортирования описаний классов Caché в клиентское приложение, используется позднее связывание для определения типов данных. Приведем пример, в котором создается объект уже известного класса Sample.Person и сохраняется в БД.
Uses ComObj;
Var
Factory : Variant;
Pers: Variant;
procedure Start();
Begin
Factory := CreateOleObject( 'CacheObject.Factory');
Factory.Connect( 'cn_iptcp:127.0.0.1[1972]:Samples');
Pers := Factory.New('Sample.Person');
Pers.Name='Сергей';
Pers.sys_Save;
End;
Эта методика по работе с объектами Caché очень удобна в первую очередь из за своей близости по синтаксису работы с атрибутами объектов языку, используемому при описании серверной логики в Caché. Поддерживается каскадный точечный синтаксис, "свизлинг" (загрузка зависимых объектов при обработке серии объектов, связанных ссылками) и другие конструкции Caché Object Script. В приложении на Delphi программа, обходящая свойство-список ссылок на хранимые объекты отличается от аналогичной программы на Caché Object Script только наличием точек с запятой в конце выражений. Это позволяет очень быстро реализовывать клиентские приложения, использующие Factory в качестве основы взаимодействия с БД.
Вывод
Итак, Caché предоставляет действительно очень широкие возможности по созданию клиентских приложений. Вне зависимости от выбора среды разработки, операционной системы и технологии программирования, разработчики всегда получают мощный объектный инструмент для описания сложной логики и классический реляционный способ работы с данными для использования стандартных утилит и компонентов.