Лекции №27,28 (16 и 21.12.2004)

advertisement
Объектно-ориентированные СУБД.
 ODMG = Object Data Management Group: разработка
стандарта для объектно-ориентированных СУБД
 ODL = Object Definition Language: объектноориентированный подход к разработке БД.
 OQL = Object Query Language: запросы к ООБД со
структурой, описываемой ODL в виде подобном SQL.
Краткий обзор ODL.
Объявление класса включает:
1. Имя класса.
2. Объявление ключей (необязательное).
3. Объявление пространства (extent) = имя для множества
текущих объектов класса
4. Объявления элементов. Элемент является аттрибутом,
отношением или методом.
Объявление классов в ODL.
class <name> {
elements = attributes, relationships, methods
}
Объявление элементов.
attribute <type> <name>;
relationship <rangetype> <name>;
Отношения(связи) определяются между объектами; аттрибуты
используют не-объектные значения, например, целые числа.
Пример метода.
float gpa(in string) raises(noGrades)
 float = тип возвращаемого значения.
 in: указывает режим использования аргумента
(предположительно, имени студента) – только-чтение,
 другие режимы: out, inout.
 noGrades является исключением, которое может быть
выставлено методом gpa.
Отношения (связи) ODL.
 Поддерживаются только бинарные отношения (связи) между
объектами.
 Множественные отношения(связи) требуют дополнительно
поддерживающего (связующего) класса, как обсуждалось
для E/R моделей.
 Связи между классами объектов описываются взаимообратными парами. Например, связь Sells между beers и bars
представлено связью в bars, где представляет сорта
продаваемого в баре пива, и связью в beers, где предсталяет
множество баров, в которых продается данный сорт пива.
 Связь «многие-к-многим» имеет тип множество (коллекция) в
обоих направлениях.
 Связь «многие-к-одному» имеет тип множество на стороне
«одного» и простое имя класса на стороне «многих».
 Связь «один-к-одному» имеет в качестве типа простое имя
класса в обоих направлениях.
Пример.
class Beers {
attribute string name;
attribute string manf;
relationship Set<Bars> servedAt
inverse Bars::serves;
relationship Set<Drinkers> fans
inverse Drinkers::likes;
}
 Элемент из другого класса указывается при помощи
<имя_класса>::<имя_элемента>
 Множественный тип образуется при помощи Set<имя_типа>.
class Bars {
attribute string name;
attribute Struct Addr {string street, string city, int zip} address;
attribute Enum Lic {full, beer, none} licenseType;
relationship Set<Drinkers> customers
inverse Drinkers::frequents;
relationship Set<Beers> serves
inverse Beers::servedAt;
}
 Структурированные типы имеют имя и список пар типаттрибут, заключенный в фигурные скобки.
 Перечислимый тип имеет имя и список значений,
заключенный в фигурные скобки.
class Drinkers {
attribute string name;
attribute Struct Bars::Addr address;
relationship Set<Beers> likes
inverse Beers::fans;
relationship Set<Bars> frequents
inverse Bars::customers;
}
Заметьте повторное использование типа Addr.
Система типов в ODL.
 Базовые типы: int, real/float, string, перечислимые типы и
классы.
 Конструкторы типов: Struct – для структур for structuresб и 5
типов коллекций: Set, Bag, List, Array, Dictionary.
 Тип связи может быть классом или коллекцией класса.
Связь «многие_к_одному».
 Не используйте коллекцию для связи на стороне «многие».
Пример. Drinkers имеют любимое пиво.
class Drinkers {
attribute string name;
attribute Struct Bars::Addr address;
relationship Set<Beers> likes
inverse Beers::fans;
relationship Beers favoriteBeer
inverse Beers::realFans;
relationship Set<Bars> frequents
inverse Bars::customers;
}
 Также нужно добавить к Beers:
relationship Set<Drinkers> realFans
inverse Drinkers::favoriteBeer;
Пример множественных связей.
Рассмотрим тернарную связь bars-beers-prices. Мы должны
создать связующий класс BBP.
class Prices {
attribute real price;
relationship Set<BBP> toBBP
inverse BBP::thePrice;
}
class BBP {
relationship Bars theBar inverse ...
relationship Beers theBeer inverse ...
relationship Prices thePrice
inverse Prices::toBBP;
}
 Обратные связи для theBar, theBeer должны быть добавлены к
Bars, Beers.
 В данном конкретном случае лучше было бы не создавать
класс Prices, а сделать price аттрибутом BBP.
 Заметьте, что ключи не обязательны.Notice that keys are
optional.
 BBP не имеет ключей, но не является здесь слабым.
Существующий внутренний идентификатор объекта
достаточен для различения объектов класса BBP.
Роли в ODL.
Имена связей описывают роли в них объектов.
Пример. Супруги и друзья-посетители.
class Drinkers {
attribute string name;
attribute Struct Bars::Addr address;
relationship Set<Beers> likes
inverse Beers::fans;
relationship Set<Bars> frequents
inverse Bars::customers;
relationship Drinkers husband
inverse wife;
relationship Drinkers wife
inverse husband;
relationship Set<Drinkers> buddies
inverse buddies;
}
 Заметьте, что указание класса Drinkeкs:: является не
обязательным, когда обратная связь задана на том же
классе.
Подклассы в ODL.
При описании подкласса после его имени указывается имя
надкласса(суперкласса), отделенное от имени подкласса
двоеточием.
Пример.
Эль является пивом с дополнительным аттрибутом – цветом.
class Ales:Beers {
attribute string color;
}
 Объекты класса Ales наследуют все аттрибуты и методы
класса Beers.
 В то время как E/R сущности могут присутствовать и в
классе и в подклассе, в ODL предполагается, что каждвй
объект является членом только одного класса.
Ключи в ODL.
Указываются при помощи ключевого слова key(или keys) и
списка аттрибутов, образующих ключ. Описание ключа
помещается в скобках после имени класса вместе с описанием
пространства объектов(экстента).
 Можно указать несколько списков аттрибутов,
описывающих альтернативные ключи.
 Скобки могут использоваться для группирования
аттрибутов одного ключа
 Так, например, (key(a1, а2, ..., an )) означает один ключ,
состоящий из всех n аттрибутов, для (key a1, а2, ..., an ) –
каждый аi является отдельным ключом.
Пример.
class Beers
(key name)
{
attribute string name ...
...
}
 Помните: ключи не являются обязательными в ODL.
Внутренний идентификатор (ID) объекта достаточен для
различения объектов, имеющих одинаковые значения
атрибутов.
Пример: несколько многоаттрибутных ключей.
class Courses
(keys (dept, number), (room, hours))
{
...
}
Перевод ODL в отношения.
1. Классы без связей переводятся в отношения также как
множества сущностей, однако при этом появляется
несколко новых проблем.
2. Классы со связями:
a) Рассматривать связи отдельно, как для E/R диаграмм.
b) Присоединить связь « многие-к-одному» к отношению
для «многих».
Классы ODL без связей.
 Проблема: ODL позволяет создавать типы аттрибутов на
основе структур и коллекций.
 Для структуры: создается один аттрибут для каждого
элемента структуры.
 Множество(Set): создается один кортеж для каждого
элемента множества.
 Что, если имеется более одного множества среди
аттрибутов класса? В таком случае создается один
кортеж для каждой комбинации элементов из множеств.
 Проблема: ODL класс может не иметь ключей, но мы
должны иметь ключ в отношении для пердсталения
идентификатора объекта.
Пример.
class Drinkers (key name) {
attribute string name;
attribute Struct Addr { string street, string city, int zip
} address;
attribute Set<string> phone;
}
name
street
city
zip
phone





n1
s1
c1
z1
p1
n1
s1
c1
z1
p2
...
Сюрприз: ключ для класса (name) не является ключом для
отношения (name, phone).
name в классе определяет уникальный объект, включая
множество телефонов.
name в отношении не определяет единственным образом
кортеж.
Поскольку кортежи не являются идентичными объектам
класса, то это не может считаться несогласованностью
Нарушение НФБК: необходимо отделить name-phone.
ODL связи.
 Если связь – «многие-к-одному» от А к В, поместить ключ
класса B в отношение для класа A.
 Если связь – «многие-к-многим», мы вынуждены дублировать
A-кортежи как в случае объекта ODL с аттрибутом типа
множество.
 Было бы удобнее создать отдельное отношения для связи
«многие-к-многим»? В любом случае мы бы пришли к этому в
ходе НФБК декомпозиции.
Пример.
class Drinkers (key name) {
attribute string name;
attribute string addr;
relationship Set<Beers> likes
inverse Beers::fans;
relationship Beers favorite
inverse Beers::realFans;
relationship Drinkers husband
inverse wife;
relationship Drinkers wife
inverse husband;
relationship Set<Drinkers> buddies
inverse buddies;
}
Drinkers(name, addr, beerName, favBeer, wife,buddy)
Проведем декомпозицию к 4НФ
ФЗ: name –> addr favBeer wife
MФЗ: name ->->beerName, name ->-> buddy
Результат декомпозиции:
Drinkers(name, addr, favBeer, wife)
DrBeer(name, beer)
DrBuddy(name, buddy)
Объектный язык запросов (OQL).
Мотивировка.
Реляционные явыки страдают от несоответствия потоков данных
для их связи с обычными явыками типа C или C++.
 Модели данных, используемые C и SQL, совершенно отличны,
например, C не имеет отношений, множеств или наборов в
качестве своих примитивных типов; C можно назвать
обрабатывающим кортеж-в-один-момент, SQL – отношение-водин-момент.
 OQL является попыткой OO сообщества пользователей
расширить язвки типа C++ SQL-типа отношение-в-одинмомент возможностями.
OQL типы.
 Базовые типы: string, int, real, и т.д. плюс имена классов.
 Конструкторы типов:
 Struct для структур.
 Коллекции: set, bag, list, array.
 Подобно ODL, но нет ограничений на количество применений
конструктора типов.
 Set(Struct()) и Bag(Struct()) выполняют специальную роль
подобно отношениям.
OQL использует ODL в части определения схемы.
 Для каждого класса мы можем определить пространство
объектов(extent) = имя для текущего множества объектов
класса.
 Необходимо ссылаться на пространство объектов (не имя
класса) в запросах к базе данных.
Пример.
class Bar
(extent Bars)
{
attribute string name;
attribute string addr;
relationship Set<Sell> beersSold
inverse Sell::bar;
}
class Beer
(extent Beers)
{
attribute string name;
attribute string manf;
relationship Set<Sell> soldBy
inverse Sell::beer;
}
class Sell
(extent Sells)
{
attribute float price;
relationship Bar bar
inverse Bar::beersSold;
relationship Beer beer
inverse Beer::soldBy;
}
Выражения для доступа к объектам и аттрибутам.
Пусть x – объект класса C.
 Если a - аттрибут C, то x.a = значение аттрибута а для
объекта х.
 Если r – связь класса C, то x.r = значение, с которым x
связан через r.
 Это может быть объек или коллекция объектов в
зависимости от типа r.
 Если m – метод класса C, то x.m(...) является результатом
применения m к объекту x.
Примеры.
Пусть s – переменная типа Sell.
 s.price = значение price для объекта s.
 s.bar.addr = адрес бара используемого в s.
 Замечание: повторное использование . («точки») допустимо,
поскольку s.bar является объектом, а не коллекцией.
Пример недопустимого использования «точки».
b.beersSold.price, где b – объект типа Bar.
 Почему недопустимо? Потому что b.beersSold является
множеством объектов, а не отдельным объектом.
OQL Select-From-Where.
SELECT <список значений>
FROM <список коллекций и типичных элементов>
WHERE <условие>
 Коллекции в списке FROM могут быть:
1. Пространством объектов(extent).
2. Выражением со значением-коллекцией.
 За коллекцией идет имя типичного элемента(по аналогии с
переменной-кортежем) с необязательным AS перед ним.
Пример.
Получить меню для бара Joe.
SELECT s.beer.name, s.price
FROM Sells s
WHERE s.bar.name = "Joe's Bar"
Отметьте использование двойных кавычек в OQL.
Другой способ получить тот же результат, используя объекты
класса Bar.
SELECT s.beer.name, s.price
FROM Bars b, b.beersSold s
WHERE b.name = "Joe's Bar"
Заметьте, что типичный элемент b в первой коллекции списка
FROM используется для определения второй коллекции.
Типичное использование.
 Если x является объектом, можно уточнять выражения
доступа к х подобно тому как это сделано в выражениях s,
s.beer, s.beer.name.
 Если x является коллекцией, его можно использовать в
списке FROM, как b.beersSold было использовано выше,
чобы получить доступ к аттрибутам x.
Использование типов результата.
 По умолчанию: результатом SELECT является набор структур
с полями, взятыми из конечных имен в выражениях (путях)
доступа списка SELECT.
Пример.
SELECT s.beer.name, s.price
FROM Bars b, b.beersSold s
WHERE b.name = "Joe's Bar"
Имеет тип результата:
Bag( Struct(
name: string,
price: real
)
)
Переименование полей.
Поставьте желаемое имя с двоеточием перед путем доступа.
Пример.
SELECT beer: s.beer.name, s.price
FROM Bars b, b.beersSold s
WHERE b.name = "Joe's Bar"
имеет тип результата:
Bag( Struct(
beer: string,
price: real
)
)
Изменение типа коллекции.
Используйте SELECT DISTINCT для получения множества
структур вместо набора структур.
SELECT DISTINCT s.beer.name, s.price
FROM Bars b, b.beersSold s
WHERE b.name = "Joe's Bar"
Используйте ORDER BY для получения списка структур.
joeMenu =
SELECT s.beer.name, s.price
FROM Bars b, b.beersSold s
WHERE b.name = "Joe's Bar"
ORDER BY s.price ASC
 ASC = по возрастанию (умолчание); DESC = по убывавнию.
Из списка структур можно извлекать отдельную структура также
как из массива, например,
cheapest = joeMenu[0].name;
Download