Кубанский государственный университет
Опубликован: 24.12.2013 | Доступ: свободный | Студентов: 682 / 9 | Длительность: 24:28:00
Лекция 10:

Объектные модели данных

Упражнение 1

Установите, будет ли уничтожен глобал, если связанная с ним таблица будет удалена командой DROP.

Подведем итоги. В Cache (рисунок 10.21) реляционной таблице соответствует класс без параметров, методов и запросов. Все свойства общедоступны. Способ хранения изменяться не может.

Каждому объекту некоторого класса соответствует строка таблицы и узел в дереве глобала. Естественно, что вне СУБД Cache можно предложить другие отображения между деревьями, таблицами, классами и объектами.

Отображение классов в таблицы и таблицы в дерево

Рис. 10.21. Отображение классов в таблицы и таблицы в дерево
Наследование

Одно из существенных отличий объектной модели от реляционной в том, что классы могут быть наследниками других классов. Разберемся с некоторыми особенностями наследования в Cache.

Создадим класс Human следующей структуры:

Class User.Human Extends %Persistent
{
Property Pass As %String(MAXLEN = 11);
// серия и номер паспорта
Property Name As %String(MAXLEN = 20);
//имя
}

Класс-наследник Student расширяет базовый класс свойством NZach — номер зачетной книжки

Class User.Student Extends User.Human
{
Property NZach As %String(MAXLEN = 10);
}

В SQL-представлении появляются две таблицы Human и Student, причем поля Name и Pass в таблице Student будут виртуальными. То есть, при создании новой записи в таблице Student значения этих полей сохраняются в таблице Human и информация о них извлекается по внутренней ссылке.

Создать новый экземпляр класса Student можно двумя способами: sql-запросом или средствами ObjectScript.

В классе Human создадим объект Петр ("Петр", "0305 855637"), а в классе Student — объект Иван ("Иван", "0305 163788", "8765").

Данные обоих классов (родителя и наследника) помещены в один глобал ^User.HumanD (лиситинг 10.11).

^User.HumanD=2
^User.HumanD(1)=$lb("","0305 855637","Петр")
^User.HumanD(2)=$lb("~Student","0305 163788","Иван")
^User.HumanD(2,"Student")=$lb("8765")
Пример 10.11. Объекты классов Human и Student

А вот содержимое таблиц Human и Student, полученное запросами вида SELECT * выглядит неожиданно с точки зрения реляционного народа (таблицы 10.6 и 10.7). Приходится признать, что в реляционной ипостаси Cache наследование реализуется.

Таблица 10.6. Содержимое таблицы Human
# ID Name Pass
1 1 Петр 0305 855637
2 2 Иван 0305 163788
Завершено
Таблица 10.7. Содержимое таблицы Student
# ID NZnach Name Pass
1 2 8765 Иван 0305 163788
Завершено

С точки зрения здравого смысла всё правильно. Студент тоже человек (хотя, кто-то из преподавателей не всегда с этим не согласится).

Особенность множественного наследования в том, что все компоненты первого класса в списке родительских классов наследуются потомками. Затем для каждого следующего в списке родительского класса наследуются свойства, методы и параметры. Если имена элементов встречаются повторно, то они перекрываются новыми элементами, так что фактически наследуются повторяющийся элемент последнего класса.

Сериализуемые объекты

На первый взгляд кажется, что сериализуемые объекты в реляционном представлении приводят к появлению двухуровневых шапок таблиц, которые, как будет показано в разделе 10.3, характерны для объектно-реляционной модели. Покажем, что в объектной модели это не так. Создадим встроенный класс Address:

Class User.Address Extends %SerialObject {
Property City As %String; Property State As %String; 
}

Создадим класс Person в виде:

Class User.Person Extends %Persistent
{
Property Name As %String; Property YearOB As %Integer; Property Home As Address;
}

Создадим объект класса Person:

S p=##class(User.Person).%New()
S p.Name="Nick", p.YearOB=1984, p.Home.City="NewYork" S p.Home.State="NY" D p.%Save()

Образовался глобал:

^User.PersonD=1
^User.PersonD(1)=$LB("","Nick","1984",$LB("NewYork","NY"))

Видим, что объект сериализуемого класса в глобале представляется списком

$LB("NewYork","NY")

В SQL-проекции инструкцией SELECT * ... выберем всё содержимое таблицы Person (таблица 10.8). Обращаем внимание на появление столбцов с именами Home_City и Home_State, образованными соединениями имени атрибута Home из класса Person и имен атрибутов City и State из класса Address. Это позволяет избежать появления двухуровневой шапки в таблице и, тем самым, не выходить за рамки реляционных таблиц.

Таблица 10.8. Результат с синтезированными именами столбцов
# ID Name YearOB Home_City Home_State
1 1 Nick 1984 New York NY
Завершено

В SQL-проекции эти столбцы действительно существуют и к ним можно обращаться по имени. Пример такого запроса:

SELECT Name, Home_City FROM Person
Индексы в объектной модели

Индексы в объектной модели Cache можно создать тремя способами:

  • SQL-командой CREATE INDEX в реляционном представлении класса;
  • непосредственно в коде определения класса;
  • с помощью мастера создания индексов.

В реляционной модели инструкция создания индекса:

CREATE   [UNIQUE   |   BITMAP   |   BITSLICE  ]   INDEX index-name ON [TABLE] [имя_схемы.]имя_таблицы (имя_поля, ...)

Индексы bitslice ускоряют работу с диапазонами, в том числе вычисления групповых функций.

Синтаксис строки определяющей индекс в описании класса:

INDEX имя_индекса
ON список_атрибутов [список_ключевых_слов];

Например, в созданном нами классе Person древесный индекс на свойство Name в теле класса может быть записан строкой

Index NameIDX On Name;

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

 Index NamelDX On Name [type=standard];

Для побитового индекса type= bitmap, третий вариант bitslice.

Уникальный индекс определяется ключевым словом unique. Например, индекс для ИНН, который имеют не все люди, может быть определён фразой:

Index INNIDX on INN [Unique];

В стандартном индексе можно хранить не только идентификаторы объектов, но и данные. Достаточно в описание индекса включить секцию Data:

Index NameIDX On Name [Data=(YearOB)];

Теперь запросы к столбцам Name и YearOB потребуют только данных из файла Personl. Индексами можно управлять и непосредственно из программы используя метод %BuildIndices() класса %Persistent. Например, для перестроения всех индексов класса Person, у которого уже созданы объекты, следует набрать

Set ss= ##class(USER.Person).%BuildIndices()

Если же некоторые из перечисленных индексов были удалены из определения класса, то сначала следует вызвать метод %PurgeIndices() , так как метод %BuildIndices() не сможет удалить старые значения индексного глобала. Простой перекомпиляции класса в этом случае не достаточно.

Для создания индекса с помощью мастера в студии нажмите кнопку "Индекс" со знаком молнии, либо наберите в главном меню "Класс > Добавить > Индекс", затем задайте имя индекса и в следующем окне выберите тип индекса (рисунок 10.22).

Задание типа индекса

Рис. 10.22. Задание типа индекса

В реляционной проекции объектной модели единственным ключом может быть суррогатный ключ OID, но, выбрав опцию "Первичный ключ" можно задать индекс, обеспечивающий уникальный выбор объекта.

Опция IDKEY задаёт свою идентификацию объекта.

Вариант Extent обеспечивает создание индекса ускоряющего выборки всех объектов экстента (в Cache под экстентом понимается набор объектов класса и всех его подклассов).

Далее для древесного индекса задаётся список свойств, на которых он строится. Затем необходимо выбрать способ сортировки каждого выбранного свойства, определяемый параметром COLLATION. Перечень вариантов сортировки приведен в документации Cache.

В панели "Данные индекса" можно перечислить свойства класса, значения которых будут сохраняться в индексе.

Запросы в описании класса

Выбираем кнопку "Новый запрос" либо в основном меню проходим путь "Класс > Добавить > Запрос". Затем называем имя запроса и выбираем способ его реализации (SQL или пользовательский код). Если запрос строится не на SQL, придется самим написать три метода класса, определяющие его работу. Это QueryExecute(), QueryFetch() и QueryClose(), где Query —имя запроса.

После этого перечисляются входные параметры, если они есть. Для каждого из параметров задаётся имя, тип и, может быть, значение по умолчанию.

В панели "Колонки" определите порядок следования столбцов таблицы, включаемых в результат запроса.

Остаётся перечислить критерии отбора объектов и указать порядок сортировки результата.