Объектные модели данных
10.3.3 Методы
Различают методы-члены класса, методы конструктора, методы сравнения и статические методы.
Методы — члены класса и методы конструкторов по умолчанию были рассмотрены в предыдущем разделе.
Методы конструкторов создаваемых пользователем
Построим пользовательский конструктор в типе person_typ2.
CREATE OR REPLACE TYPE person_typ2 AS OBJECT ( name VARCHAR2(4 0), dob DATE, — дата рождения phone VARCHAR2(12), — спецификация метода, возвращающего возраст MEMBER FUNCTION Age RETURN NUMBER, — возвращаемое значение CONSTRUCTOR FUNCTION person_typ ( p_name VARCHAR, p_dob DATE ) RETURN SELF AS RESULT );
Ключевые слова CONSTRUCTOR FUNCTION применяются для задания пользовательских конструкторов. Фраза RETURN SELF AS RESULT означает, что конструктор вернёт объект типа person_typ2.
Создаём тело типа:
CREATE OR REPLACE TYPE BODY person_typ2 AS MEMBER FUNCTION Age RETURN NUMBER IS BEGIN — вычисление возраста RETURN ROUND(MONTHS_BETWEEN(sysdate, birthday)/12); END; CONSTRUCTOR FUNCTION person_typ ( p_name VARCHAR, p_dob DATE ) RETURN SELF AS RESULT IS BEGIN SELF.name := p_name; SELF.dob := p_dob; SELF.phone := '2-222-222'; RETURN; END; END;
Слово SELF указывает на создаваемый объект. Так, присваивание
SELF.name := p_name;
означает, что атрибуту name создаваемого объекта передаётся значение, присвоенное формальному параметру p_name конструктора.
Проверьте работу конструктора по умолчанию и пользовательского конструктора, позволяющего создать объект типа person_typ2 с двумя параметрами — именем и датой рождения. А вот телефон у таких объектов всегда один и тот же 2-222-222.
Методы сравнения (MAP и ORDER)
В предопределённых скалярных типах всегда задаются отношения эквивалентности и порядка. Именно поэтому возможно сравнение и упорядочение значений типа. В объектных типах эти отношения должен задать разработчик. Вы не сможете употреблять фразу ORDER BY в запросах, а для установления эквивалентности двух объектов придётся сравнивать какие-то поля классов.
Методы сравнения MAP и ORDER позволяют задать эквивалентность и порядок на объектном типе данных.
В объектной модели Oracle предусмотрены определяемые пользователем методы MAP и ORDER, позволяющие ввести отношение порядка.
Метод MAP
Метод MAP это функция член типа (member function) без аргументов с именем сопровождаемым ключевым словом MAP. Она может возвращать значения только следующих типов: DATE, NUMBER, CHAR, VARCHAR2 или REAL.
В спецификации типа для задания метода MAP необходимо ввести фразу
MAP MEMBER FUNCTION имя_функции RETURN тип_данных.
В описании тела типа задаётся обычное описание функции члена типа перед которым помещается ключевое слово MAP:
MAP MEMBER FUNCTION имя_функции RETURN тип_данных IS описание_функции;
Приведём простейший пример реализации метода MAP, в котором точка характеризуется тремя параметрами, а эквивалентность точек определяется по двум из них:
CREATE OR REPLACE TYPE point_typ AS OBJECT ( x NUMBER(3), y NUMBER(3), weight NUMBER(4,1), distance NUMBER(4,1), MAP MEMBER FUNCTION point_ecv RETURN NUMBER ); CREATE OR REPLACE TYPE BODY point_typ AS MAP MEMBER FUNCTION point_ecv RETURN NUMBER IS BEGIN distance := x**2+y**2; RETURN distance; END; END;
Теперь можно сравнивать объекты типа point_typ по значениям, возвращаемым функцией point_ecv, например, используя self.distance.
Метод ORDER
Это функция с одним аргументом объектного типа, возвращающая значение: — 1, если параметр больше SELF; 1, если параметр меньше SELF; 0, если параметр равен SELF. Для одного типа нельзя одновременно использовать и MAP и ORDER. Метод ORDER моделирует парное сравнение, используемое в психологии и социологии. Когда удаётся сравнить объекты исследования попарно, но не возможности сравнить несколько объектов сразу.
Статические методы
Методы-члены, методы сравнения и конструкторы задают поведение экземпляров объектного типа. Параметр SELF обеспечивает им доступ к атрибутам объектов.
Статические методы определяют поведение объектного типа в целом, а не отдельных его экземпляров. Поэтому параметром SELF они пользоваться не могут. Чаще всего статические методы используются для задания вспомогательных функций, например, приведения объекта к другому типу.
10.3.4 Наследование
Используется единичное наследование, при котором, как обычно, тип-потомок наследует от предка все атрибуты и методы. Потомок обязательно расширяет тип-предок дополнительными атрибутами и, может быть, переопределяет методы.
Фраза NOT FINAL в конце определения типа делает наследование возможным. Этот же результат достигается по умолчанию. Фраза FINAL запрещает наследование.
Пример (заимствован из документа "Objeci-Relational Developer's Guide" B28371-03):
Создаём тип person_typ для которого возможно наследование.
CREATE OR REPLACE TYPE person_typ AS OBJECT ( id NUMBER, name VARCHAR2(30), phone VARCHAR2(30), MEMBER FUNCTION show RETURN VARCHAR2) NOT FINAL; CREATE OR REPLACE TYPE BODY person_typ AS MEMBER FUNCTION show RETURN VARCHAR2 IS BEGIN RETURN 'Id: ' || TO_CHAR(id) || ', Name: ' || name; END; END;
Заметим, что при необходимости можно запретить наследование командой
ALTER TYPE person_typ NOT FINAL;
и вновь разрешить его. Создаём подтип (наследуемый тип). Сначала определяем спецификацию типа
CREATE OR REPLACE TYPE student_typ UNDER person_typ ( dept_id NUMBER, major VARCHAR2(30), OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2) NOT FINAL;
затем тело типа
CREATE OR REPLACE TYPE BODY student_typ AS OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS BEGIN RETURN (self AS person_typ).show || ' -- Major: ' || major; END; END;
Слово UNDER в спецификации типа обозначает наследование. Major это профилирующий предмет, изучаемый студентом.
10.3.5 Коллекции
Коллекции могут использоваться в качестве типов данных полей объектных таблиц и атрибутов временных объектов. Они позволяют хранить в столбце не атомарные значения. Существует два типа коллекций:
- Вложенные таблицы (nested tables) - одномерные, неограниченные коллекции однородных элементов.
- Массивы переменной длины (variable-size arrays) VARRAY представляют одномерную ограниченную коллекцию однородных элементов. В отличие от вложенных таблиц, порядок элементов при обработке и запоминании сохраняется. Количество элементов от 0 до указанного при определении максимального значения. Обращаются к элементам коллекции по индексу, как в массиве.
Важнейшее преимущество коллекции - возможность передать ее всю между базой и PL/SQL за одну последовательность чтений, что может существенно увеличить скорость обмена.
Массивы переменной длины
Реализованы как в SQL, так и в PL/SQL. В SQL прямое обращение к элементам невозможно, но весь массив VARRAY можно извлечь в переменную PL/SQL типа VARRAY. Возможность обмена массивами вместо обращения к подчиненной таблице может существенно увеличить производительность. При определении указывается максимальная длина массива. Вложенность массивов не поддерживается, то есть VARRAY не может содержать другие VARRAY.
Простой пример: Пусть необходимо хранить в таблице идентификатор, фамилию, имя, отчество (одним полем) и до трех номеров телефонов. Определим тип Phones_typ как коллекцию типа VARRAY
CREATE TYPE phones_typ AS VARRAY(3) OF CHAR(9);
Теперь определим таблицу этого типа
CREATE TABLE clients ( id NUMBER, name VARCHAR2(50), phones Phones_typ );
Вставим в неё строку
INSERT INTO clients VALUES(42,'Сидоров Иван Петрович', phones_typ( '11-22-66', '57-23-56'));
Получить всю информацию о массивах VARRAY можно из представления словаря user_varrays, а обо всех доступных пользователю массивах из представления all_varrays. Достаточно выполнить запрос вроде
SELECT * FROM user_varrays;
Вложенные таблицы
Таблица может содержать несколько вложенных таблиц, но глубина вложения единица. На вложенную таблицу можно создавать триггеры и индексы. У любого такого индекса к ключу добавлен идентификатор объекта (OID) родительской строки, поэтому прямой доступ к строке вложенной таблицы невозможен.
Рассмотрим простой пример.
Для задания вложенной таблицы создадим объектный тип Doc_typ:
CREATE TYPE Doc_typ AS OBJECT ( dno CHAR(5), dname CHAR(20), dtype CHAR(3) );
Используя его, создадим тип вложенной таблицы:
CREATE TYPE Documents_typ AS TABLE OF Doc_typ;
Теперь определим таблицу Document:
CREATE TABLE Document ( dno CHAR(5) PRIMARY KEY, dname CHAR(20) UNIQUE, docum Documents_typ ) NESTED TABLE docum STORE AS docum_table;
С помощью команды describe обнаруживаем, что таблица doc-um_table действительно существует.
Информация о всех вложенных таблицах получается запросом
SELECT * FROM user_nested_tables;
Сравним коллекции между собой. Обе они представляют упорядоченные коллекции однородных элементов. При использовании их как типов для столбцов выявляется одно важное отличие. VARRAY ограничен в размере и хранит свои данные вместе с данными родительской таблицы. Данные во вложенных таблицах хранятся в специальных вспомогательных таблицах и предел их роста не устанавливается.
10.3.6 Объектные представления
Существуют объектные представления (object view), которые могут создаваться над реляционными данными. Все расширения DML, предназначенные для работы с объектными таблицами, поддерживают и объектные представления. На их основе можно создавать объектно-ориентированные приложения, не модифицируя существующие реляционные схемы. Свойства объектных представлений подобны свойствам объектных таблиц.
Создадим таблицу и тип данных:
CREATE TABLE emp_table ( empnum NUMBER(5), ename VARCHAR2(20), salary NUMBER(9,2), job VARCHAR2(40) );
Заполним её
INSERT INTO emp_table VALUES(33, 'Иванов', 25000, 'начальник'); INSERT INTO emp_table VALUES(33, 'Петров', 20000, 'разработчик');
Создадим тип
CREATE OR REPLACE TYPE employee_typ AS OBJECT ( empno NUMBER(5), ename VARCHAR2(20), salary NUMBER(9,2), job VARCHAR2(20) );
и объектное представление
CREATE OR REPLACE VIEW emp_view2 OF employee_t WITH OBJECT OID (empno) AS SELECT e.empnum, e.ename, e.salary, e.job FROM emp_table e WHERE job = 'разработчик';
Объектное представление выглядит для пользователя как объектная таблица со строками типа employee_typ. Каждая ее строка имеет уникальный объектный идентификатор.
В базе данных, состоящей из реляционной и объектно-реляционной частей, можно, обращаясь к реляционным таблицам через объектные представлениям, рассматривать всю базу как объектно-реляционную.
10.3.7 Сравнение полученных объектных моделей данных
Итак, изучены две, технически достаточно различные объектные модели. Сравним их, имея в виду, что речь идёт о конкретных решениях, а не о соотношениях объектной и объектно-реляционной моделей данных вообще.
Сначала перечислим общие особенности. Это, в первую очередь, появление персистентных классов, объекты которых хранятся в базе данных. Как следствие, использование двух объектных ссылок OID и OREF, обеспечивающих доступ к объектам в памяти и на диске.
Вторая ожидаемая особенность —усложнённая типизация, появление векторных типов конструируемых пользователем, и наследование.
Третье общее свойство — широкое использование методов, в том числе предопределённых в общих предках, методов-конструкторов и методов-членов класса. Но это конечно не особенность, а общее свойство всех объектных систем. Важно, что использование методов позволяет существенно расширить возможности для организации активности базы.
Отличия изученных моделей определяются, прежде всего, использованными существенно различающимися структурами хранения данных и возможностями доступа к данным. В частности, в объектно-реляционной модели все данные общедоступны, а в объектной возможен вариант private. Единая архитектура Cache вызвала встраивание в класс запросов, которых нет в объектно-реляционной модели. Правда, в ней можно написать метод эквивалентный запросу. Отличаются системы классов / типов и принятые модели наследования.
Поскольку Cache позволяет пользователю гораздо больше "самостоятельности", чем Oracle, в ней можно изменять структуры хранения и в пользовательских программах иметь доступ к промежуточным результатам работы СУБД. Но это отличия реализаций, а не моделей.
Ещё один, наверное неожиданный, результат использования единой архитектуры Cache — "втаскивание" наследования в табличную модель данных.
Полезно проследить, какие из свойств моделей данных вызываются потребностями моделирования бизнеса, а какие вытекают из принятых ранее проектных решений, в первую очередь, касающихся использованных структур хранения.