SQL и ООП

Я не предлагаю вшивать ООП возможности непосредственно в SQL. Да у меня и нет возможности сделать это – написание SQL-серверов дело сложное. Предлагается сделать прослойку между объектным языком запросов (OQL) и стандартным SQL (описано без конкретной привязке к определенному серверу). Пишем методы в OQL и ретранслируем их в SQL. Исходные тексты можно хранить в специальных таблицах той же базы. Итак о реализации.

Основные термины

Класс данных – обычная таблица в реляционной БД. Единственное требование наличие уникального первичного ключа uid, который автоматически создается ретранслятором. Объект – запись таблицы, первичный ключ аналогом ссылки на объект в обычном ООП. Data member – поля таблицы. Member function – хранимые процедуры, оперирующие объектом или классом данных. Отдельно хочу выделить абстрактный класс, объекты которого не создаются – следовательно, и таблицы нет. Поля и методы такого класса реализуются в наследниках.

Элементариные типы данных остаются теми же: строки, числа, логический тип, дата/время. Добавляются тип ссылки на другую таблицу (внешний ключ). Если это ссылка на абстрактный класс, то реализуется двумя полями, ссылка на класс и ссылка на объект.

Три кита ООП

Инкапсуляция в ООП необходима по двум причинам. Первая это разделение прав доступа на члены класса. Здесь достаточно просто, достаточно на этапе ретрансляции анализировать работу с данными разного уровня доступа. Вторая - корректное поведение (согласованность), обычно запрещается непосредственно изменять поля класса извне. В одних языках для этого используются свойства, другие обходятся setter методами. В OQL вместо запрета можно воспользоваться триггерами. Таким образом меняя поле, вы вызываете и некое поведение. Получаем нечто вроде property.

Наследование реализуется ссылкой на базовый класс, если тот не абстрактный. В абстрактном случае поля просто реализуются в наследнике.

Полиморфизм. Самое, пожалуй, тонкое место. Объекты класса имеющие виртуальные методы обязаны носить в себе не только указатель на объект (идентификатор записи таблицы), но и иднтификатор самой таблицы. Сами же виртуальные методы реализуются следующим образом:

Если ТипКласса=1 Тогда 
  МетодКласса1(Объект);
ИначеЕсли ТипКласса=2 Тогда
  МетодКласса2(Объект);
ИначеЕсли ТипКласса=3 Тогда
  МетодКласса3(Объект);
КонецЕсли;
Естественно данноe преобразование делает ретранслятор.

Новые конструкци в OQL по сравнению с SQL

В целом конструкции языка SQL остаются рабочими и только пополняются расширенями.

Служебное слово object - ссылка на объект класса для использования в дальнейшем методов и полей «через точку». Реализуется ретранслятором как uid (плюс идентфикатор класса для абстрактных классов)

SELECT object FROM MyClass INTO: MyObjectVariable

uid - фактически тоже самое, но значение числовое. Только для чтения.

this(self) - ссылка внутри метода на себя

Использование SELECT атрибутов «через точку»

SELECT Title, Author. Name, Author.Country.Name FROM Book
выдает список названия книг, имя автора и названия стран авторов. Ретранслятор преобразует это в LEFT JOIN
SELECT Title, Author. Name, Author.Country.Name FROM Book 
LEFT JOIN Author ON (Book. Author= Author.UID)
LEFT JOIN Country ON (Author. Country= Country.UID)
SELECT для абстрактных классов сводится к набору конкретных SELECT объединенных UNION

Оператор INSERT. Также как и обычная вставка, но переменная <ИмяОбъекта> ссылается на созданный объект (запись)

INSERT <ИмяОбъекта> INTO <ИмяКласса>([Поля]) VALUES ([Значения])

Оператор UPDATE. Изменяет конкретную запись

UPDATE <ИмяОбъекта> SET  <Поле>=<Значение>,…

Оператор DELETE. Удаляет запись

DELETE <ИмяОбъекта>

Множественное выполнение EXEC. Выполняется для всех объектов класса, если нужно ограничить используем обычное WHERE, если важен порядок обхода ORDER BY

EXEC <ВызовМетода>() FROM <ИмяКласса>

Триггеры

Перед модификацией - cначала вызывается триггер родительского класса (рекурсивно), потом непосредственно текущего. После модификации – наоборот: сначала текущего, потом родительского.

На главную
Hosted by uCoz