|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
2003 г
Объектно-ориентированная организация реляционных данных
|
|
NoS |
Уникальный номер отгрузки |
|
Date |
Дата отгрузки |
|
EmpID |
Идентификатор ответственного сотрудника |
|
EmpName |
Имя сотрудника |
|
GoodsID |
Уникальный артикул товара |
|
СoodsName |
Наименование товара |
|
Pieces |
Количество отгруженного товара (штуки) |
На начальном этапе мы должны
1) определить границы предметной области, выявив в ней возможные классы и объекты, для чего можно использовать существующие методы объектно-ориентированного анализа. В нашем примере такими классами могут быть классы, описывающие товары (cGoods), служащих (cEmployees) и отгрузки (cShipments).
2) нормализовать имеющуюся схему данных. В процессе нормализации мы получили несколько 3НФ отношений (первый столбец содержит имя атрибута, второй – накладываемые на него ограничения)
rStaff (информация о сотрудниках)
|
StaffID |
Primary key |
|
StaffName |
rGoods (информация о товарах)
|
GoodsID |
Primary key |
|
GoodsName |
rShipments (общие данные об отгрузках)
|
NoS |
Primary key |
|
Sdate |
|
|
StaffID |
rShipmentComments (необязательные комментарии об отгрузках)
|
NoS |
Primary key, Foreign key on rShipments.NoS |
|
Comments |
rShipmentItems(детальные данные об отгрузках)
|
NoS |
Primary key, Foreign key on rShipments.NoS |
|
GoodsID |
Primary key, Foreign key on rGoods.GoodsID |
|
Pieces |
Дальнейшие шаги по созданию схемы данных основаны на выявлении функциональных зависимостей С->R.ra между классами и ключевыми атрибутами отношений, возникших в процессе нормализации данных. Атрибут функционально зависит от класса в том случае, когда каждому объекту этого класса может соответствовать одно единственное значение атрибута. Интуитивно понятно, что подобные зависимости говорят о том, что информация в кортежах, ключи которых зависят от объекта, характеризуют этот объект и, следовательно, должна быть представлена в виде атрибутов этого объекта.
Существование таких зависимостей, однако, позволяет утверждать, что отношения в том виде, в котором они существуют после процедуры нормализации, требуют дальнейших преобразований. Суть проблемы становиться понятной, когда мы рассмотрим отношений R, атрибут rai которого функционально зависит от класса С (каждому объекту класса C соответствует одно значение атрибута rai , С->R.rai). При переходе на уровень представления эта зависимость трансформируется в существующую в соответствующем отношении R' зависимость атрибута rai от системного атрибута raOID, raOID -> rai . И в случае, если атрибут rai входит в состав ключа отношения R, можно утверждать, что соответствующее ему на уровне хранения отношение R' содержит нежелательные функциональные зависимости, что говорит о неоптимальной организации хранящихся данных.
Для оптимизации уровня хранения предлагается процедура объектной привязки, в процессе которой мы изменяем схему отношений, возникших в процессе нормализации данных. В процессе этих изменений мы минимизируем количества ключей и связей, явно задаваемых на уровне представления данных, предполагая, что соответствующие ограничения целостности данных могут реализовываться на уровне хранения О-механизмом, использующим, в частности, связанное со стержневым отношением системное поле raOID.
Описывающая предметную область схема данных, возникшая в результате объектной привязки, будет представлять собой набор классов и свойств. Заметим, что с формальной стороны "свойства" определяют существование реляционных доменов (rdom), то есть отношений. Значение "свойства" представляет собой кортеж отношения, а множество таких значений (возможно пустое или единичное), является значением отношения.
Окончательная структура данных, которая возникнет в процессе объектной привязки, выйдет за рамки реляционной модели данных (собственно, это и является целью наших построений). Однако крайне важно понимать, что структура и свойств и классов полностью определяется структурой отношений, возникших в процессе нормализации и, в свою очередь полностью определяет структуру отношений, существующих на уровне хранения. В свете этого, термины "класс" и "свойство" по сути дела вводят на уровне хранения определенные ограничения целостности данных.
Объектная привязка использует нескольких простых правил. Основное правило звучит так: если ключ отношения, возникшего в результате нормализации, полностью зависит от класса, то схема этого отношение может определять структуру объектов этого класса. Можно выделить случай, когда ключ, полностью зависящий от класса, не является внешним ключом, и не содержит поля, являющиеся внешними ключами. Будем называть такое отношение сильным (другие отношения, соответственно, являются слабыми). В качестве примера можно рассмотреть функциональную зависимоcть, сушествующую между классом cStaff и полем StaffID отношения rStaff (служащему присвоен номер).
На уровне хранения в отношении rStaff' (raOID, StaffID, StaffName) присутствует транзитивная зависимость raOID -> StaffID, StaffID -> StaffName.С другой стороны, поскольку StaffID является ключом (служащему присвоен уникальный номер), можно утверждать, что существует обратная зависимость StaffID -> raOID. По сути дела поле StaffID можно рассматривать как явно заданный ключ класса cStaff (не путать с OID!).
Обратим внимание на то, что в случае, когда ключ отношения R полностью зависит от класса, каждому объекту этого класса соответствует в точности один кортеж отношения R (служащему не может соответствовать несколько номеров). Таким образом, если рассматривать сильное отношение R как реляционный домен, на котором определены значения атрибутов класса, можно утверждать, что эти значения не могут быть группой повторения.
Учитывая то, что каждому объекту класса соответствует в точности один кортеж сильного отношения, схема сильного отношения должна использоваться как основа для описания схемы соответствующего класса (но только как основа – полная структура класса может быть гораздо сложнее, чем схема соответствующего ему сильного отношения). В нашем примере отношение rStaff является основой для класса cStaff, который может быть описан следующим образом
CLASS cStaff{StaffID AS INT GLOBAL UNIQUE;StaffName AS STRING;
}
Тем самым неявно определено свойство одноименное классу и являющее для этого класса главным, корневым. Модификатор GLOBAL UNIQUE, определяющий уникальность значение поля StaffID в объектах класса cStaff, позволяет рассматривать это поле как явно заданный ключ класса cStaff. Существование этого ключа определяется тем, что поле StaffID является ключом сильного отношения. Такому описанию класса (и корневого свойства) на уровне хранение будет соответствовать следующее отношение rStaff'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
r StaffID |
Unique |
|
r StaffName |
Аналогичные рассуждения верны для отношений rGoods, которое является основой для класса cStaff. со следующей схемой
CLASS cGoods{GoodsID AS INT GLOBAL UNIQUE;GoodsName AS STRING;
}
который будет представлен на уровне хранения отношением
rGoods'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
r GoodsID |
Unique |
|
r GoodsName |
Схема же класса, базирующегося на сильном отношении rShipments, будет гораздо сложнее схемы этого отношения. Конечно, отношение rShipments является основой схемы класса и определяет существование неявно заданного корневого свойства одноименного этому классу. Однако, и это следует из основного правила, схема отношение rShipmentComments также может определять структуру объектов класса cShipments. В данном случае полностью зависящий от класса ключ отношения является к тому же и внешним ключом. Атрибут, определенный на таком отношении, не может являться повторяющейся группой и не должен содержать более одного кортежа.
Этот случай подразумевает, что в множестве отношений, возникших после нормализации, для этого класса уже существует сильное отношение. В нашем примере атрибут NoS отношения rShipmentComments является внешним ключом, явно связывающим это отношение с первичным ключом отношения rShipments. Принимая во внимание, что отношение rShipmentComments описывает те же объекты, что и отношение rShipment, можно утверждать, что явно заданная связь rShipments.NoS <-> rShipmentComments.NoS при переходе на уровень хранения станет избыточной (избыточной в объекте), поскольку она будет дублироваться связью rShipment'. raOID <-> R0'. raOID <-> rShipmentComments'. raOID между системными атрибутами raOID стержневого отношения R0' и отношений rShipmentComments' и rShipment'. Последняя связь является системной. Она существует только на уровне хранения, на уровне же представления она задается тем, что отношения rShipment и rShipmentComments определяются как отношения, описывающие объекты одного и того же класса. Следовательно, если поля (поле) слабого отношения, описывающего некоторый класс, являются внешним ключом, связанным с ключом сильного отношения, описывающего тот же класс, то эти поля (поле) должны должно быть исключено из схемы свойства, основанного на этом отношении.
Таким образом, для оптимальной организации уровня хранения следует изменить схему отношения rShipmentComments, исключив из него атрибут NoS. Результатом этого станет свойство
PROPERTY pShipmentComments{Comments AS STRING;
}
которое должно рассматриваться как домен атрибута класса. На уровне хранения этому свойству будет соответствовать отношение
rShipmentComments'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
r Comment |
Существуют другой случай, когда явно задаваемая связь является избыточной в объекте. Рассмотрим случай, когда ключ частично зависит от класса (т.е. от класса зависят не все поля, входящие в ключ). Будет утверждать, что в том случае, если ключ отношения, возникшего в результате нормализации, частично зависит от класса, то схема это отношение также может определять структуру объектов этого класса (подразумевается, что схема отношения, ключ которого частично зависит от класса, может и не определять структуру этого класса).
В качестве примера рассмотрим отношение rShipmentItems. Первичный ключ этого отношения входят два поля, одно из которых, NoS, зависит от класса cShipments, а другое, CoodsID – от класса cGoogs. Исходя из только что сформулированного принципа, мы должны выбрать класс, схему которого должно определять рассматриваемое отношение. Целью этого выбора является адекватное представление сущностей реального мира. В нашем случае естественно предположить (поскольку мы говорим про данные, означенные как "элемент отгрузки") что схема отношение rShipmentItems должна послужить основой для определения структуры класса cShipments.
Из этого следует, что связь rShipments.NoS <->rShipmentItems.NoS является избыточной в объекте. Для оптимальной организации уровня хранения следует изменить схему отношения rShipmentItems, исключив из него атрибут NoS. Однако это изменение не будет единственным.
Поле GoodsID отношения rShipmentItems связано с первичным ключом возникшего в результате нормализации отношения rGoogs. В процессе анализа мы пришли к выводу, что rGoogs является сильным отношением, определяющем класс сGoogs. Однако, поскольку отношения rShipmentItems и rGoogs описывают объекты разных классов, эта связь не является избыточной в объекте.
В таком случае процедура объектной привязки предполагает, что если поля (поле) слабого отношения, описывающего некоторый класс, являются внешним ключом, связанным с ключом сильного отношения, описывающего другой класс, то эти поля (поле) должны быть заменены ссылкой на класс сильного отношения. Возможность такой замены обусловлено тем, что между множеством значений ключа сильного отношения и множеством уникальных идентификаторов объектов класса этого отношения, существует взаимно-однозначное соответствие. Значение явно заданного поля GoodsID (ключ класса) в объектах класса cGoods точно так же уникально, как и скрытое значение уникального объектного идентификатора и, следовательно, поле rShipmentItems.GoodsID должно быть заменено ссылкой на класс cGoods (то же самое относится и к полю StaffID отношения rShipment, которое должно быть заменено на ссылку на класс cStaff ).
Учитывая сказанное, схема отношения rShipmentItems преобразуется в следующую схему свойства ShipmentItems
PROPERTY pShipmentItems{
Good As cGoods UNIQUE;Pieces AS INT;
}
Модификатор UNIQUE определяет, что поле Good будет уникальным в группе повторения. Поскольку группа повторения свойства представляет собой значение отношения, указанный модификатор фактически определяет первичный ключа атрибута объекта. Существование такого первичного ключа следует из того, что поле rShipmentItems.GoodsID входит в состав первичного ключа отношения rShipmentItems, схема которого послужила основой схемы свойства pShipmentItems. Наличие первичного ключа в свойстве определяет, что значения этого свойства могут образовывать группу повторения, элементы которой (кортежи) должны содержать ссылки на различные объекты класса cGoods. Под "различными" здесь подразумеваются объекты, имеющие разные OID (можно предположить, что возможно переопределение операции сравнения, применимой к объектам данного класса). Свойству ShipmentItems на уровне хранения будет соответствовать отношение rShipmentItems' (отметим наличие симметричной ассоциации (raOID, …, rGoodsref, …) )
rShipmentItems'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
r Goodsref |
Primary key, Foreign key on R0. raOID |
|
r Pieces |
С учетом всего вышесказанного схема класса cShipments на уровне представления будет выглядеть следующим образом
Class cShipment{NoS AS LONG GLOBAL UNIQUE;SDate As DATE;Staff AS cStaff;ShipmentItems AS SET OF pShipmentItems;Comment pShipmentComments;
}
Поля NoS, SDate и Staff являются полями неявно заданного корневого свойства класса cShipment. На уровне представления ему будет соответствовать отношение.
rShipments'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
NoS |
UNIQUE |
|
r SDate |
|
|
r Staffref |
Foreign key on R0. raOID |
Таким образом, на уровне хранения объект класса cShipment будет представлен одним кортежем отношения rShipments' (обязательно), одним кортежем отношения rShipmentComments' (возможно), и множеством (возможно пустым) уникальных кортежей отношения rShipmentItems', причем все указанные кортежи будут связаны системным полем raOID с одноименным полем стержневого отношения R0, содержащим уникальный идентификатор этого объекта.
Еще раз подчеркнем, что схема данных, возникающая в процессе объектной привязки, определяется как анализом предметной области, так и множеством отношений, возникших в результате нормализации описывающих ее данных. В качестве иллюстрации к этой мысли рассмотрим еще один случай, когда атрибуты, входящие в ключ отношения и зависящие от класса, не являются внешним ключом. Продолжая наш пример, создадим схему данных, описывающих поставки товара на склад. Предположим, что в результате нормализации данных мы получили следующее простое отношение
rSupplyItems
|
SupplyDate |
Primary key |
Дата поставки |
|
GoodsID |
Primary key, Foreign key on rGoods.GoodsID |
Уникальный артикул товара |
|
Pieces |
Штуки, поставленные за день |
Первичный ключ этого отношения содержит поле GoodsID а, следовательно, это можно было бы предполагать, что это отношение должно определять структуру класса сGoods. Следуя этому предположению, мы должны создать свойство
PROPERTY pGoodsSupply{SupplyDate As DATE UNIQUE;Pieces AS INT;
}
которое в дальнейшем будет рассматриваться как домен (rdom) входящего в класс cGoods атрибута, который содержит информацию о поставках описываемого этим классом товара.
Однако предположим, что анализ предметной области показал необходимость создать класс cSuppliesPerDate, описывающий поставки товара за день. Следуя этому определению, можно говорить о существовании зависимости cSuppliesPerDate ->rSupplyItems.SupplyDate. Зависимый атрибут SupplyDate не является внешним ключом (хотя и входит в его состав). Отношение, являющееся сильным для класса cDaySupply, отсутствует. В таких случай процедура объектной привязки предполагает, что зависящие от класса поля, не являющиеся ни первичным, ни внешним ключом, должны быть выделены в отдельное отношения, которое и станет сильным для этого класса. В нашем случае схем должна быть изменена следующим образом
rSupplyDates
|
SupplyDate |
Primary key |
rSupplyItems
|
SupplyDate |
Primary key, Foreign key on rSupplyDates. SupplyDate |
|
GoodsID |
Primary key, Foreign key on rGoods.GoodsID |
|
Pieces |
Далее мы действуем ранее описанным способом. Поскольку связь rSupplyItems.SupplyDate -> rSupplyDates.SupplyDate является избыточной в объекте, а поле GoodsID является внешним ключом, связанным с отношением, относящимся к другому классу, окончательная схема данных, описывающая поставки должна выглядеть следующим образом
PROPERTY pSupplyItems{Good As cGoods UNIQUE;
Pieces AS INT;
}
CLASS cSuppliesPerDate {
SupplyDate AS DATE GLOBAL UNIQUE;
SupplyItems AS SET OF pSupplyItems;
}
Итак, процедура объектной привязки выполняется на основании следующих правил (порядок нестрогий). Если зависимые от класса Сi атрибуты ra отношения Rk
1) являются ключом и не являются внешним ключом, то отношение Rk является сильным и его схема может служить основой для структуры класса Сi.
2) являются внешним ключом и определяют связь с отношением описывающим…
… тот же класс Ci , то эта связь является избыточной в объекте класса Ci, поэтому атрибуты ra надо исключить из схемы Rk
… другой класс Cj , то речь идет о связи между объектами классов Ci и Cj, поэтому атрибуты ra надо заменить ссылкой на класс Cj
3) не являются ни первичным, ни внешним ключом (класс Сi не имеет сильного отношения), то атрибуты ra могут быть вычленены в отдельное отношение, являющееся для класса Ci сильным (далее как в 2).
Схема данных, возникшая в процессе объектной привязки, еще не является окончательной. Обратим внимание на то, что схема свойств pSupplyItems и pShipmentItems являются абсолютно идентичными. Этот факт соответствует мысли, что информация, описываемая этими свойствами, имеет в общем-то одинаковый смысл, а именно "количество товара". Поэтому они могут быть заменены общим свойством pGoodsItems. Соответствующее этому свойству отношение уровня хранения
rGoodsItems'
|
r aOID |
Primary key, Foreign key on R0. raOID |
|
r aoa |
|
|
r Goodsref |
Primary key, Foreign key on R0. raOID |
|
r Pieces |
будет содержать детальные данные и по отгрузкам и по поставкам. Смысловая разница между ними будет обуславливаться значением атрибута raoa: данным об отгрузках будет соответствовать атрибут ShipmentItems класса cShipments, а данным о поставках – атрибут SupplyItems класса cSuppliesPerDate. С учетом этого изменения схема данных должна будет выглядеть следующим образом.
CLASS cStaff
StaffID AS INT GLOBAL UNIQUE;StaffName AS STRING;
}
CLASS cGoods{
GoodsID AS INT GLOBAL UNIQUE;GoodsName AS STRING;
}
PROPERTY pShipmentComments{
Comments AS STRING;
}
PROPERTY pGoodsItems {
Good As cGoods PRIMARY KEY;Pieces AS INT;
}
CLASS cShipments{
NoS AS LONG GLOBAL UNIQUE;
SDate As DATE;
Staff AS cStaff;
ShipmentItems AS SET OF pGoodsItems;
Comment AS pShipmentComments;
}
CLASS cSuppliesPerDate{
SupplyDate AS DATE GLOBAL UNIQUE;
SupplyItems AS SET OF pGoodsItems;
}
В дальнейшем эта схема будет использоваться в примерах, демонстрирующих возможностей подхода. Оговоримся, что описание управляющего языка не является целью данной статьи. Стремясь сделать примеры наглядными, мы не использовали синтаксис какого-либо конкретного языка программирования: конструкции связанные с объектами близки объектным языкам, синтаксис языка запросов близок к SQL, хотя нельзя не отметить, что возможностей последнего явно недостаточно для того, что бы обращаться к сложно организованным данным.
Групповые операции. Ненавигационный доступ к данным.
Рассмотрим класс С со схемой (oa1:R1, …, oan:Rn) содержащий объекты {o1 , … ,om}. Предположим, что существует реляционный оператор
calcR = E( R1, … , Rn), <11>
где Ri – отношения (rdom), на которых определены атрибуты объектов класса С, calcR - отношение (rdom), на котором определен результат. Применим оператор E к объекту oi класса С и рассмотрим выражение oi.E(oa1, … , oan), которое, исходя из значений атрибутов {oa1, … , oan} этого объекта, вычисляет некоторое значение calcr
calcri = oi.E(oa1, … , oan) <12>
Как мы уже показали, атрибут oa объекта o на уровне хранения представлен как
s(raOID= OID, raoa = oa)(R') , где R' = rstorage(oa), <13>
или
s(raOID= OID)(A), где A = s(raoa = oa)(R'). <13'>
В последнем случае мы рассматриваем подмножество A отношения R', содержащее все значения атрибута oa всех объектов класса с. Исходя из этого, перепишем правую часть выражение <12> как
oi.E(oa1, … , oan) OєR' E( s(raOID= OIDi)(A1), … , s(raOID= OIDi)(An)) <14>
Для перечисленных далее операторов реляционной алгебры[8,10] справедливы следующие равенства:
-для объединения
s( raOID= OID)(Ak) И s( raOID= OID)(Am) = s( raOID= OID)(Ak И Am),
-для пересечения
s( raOID= OID)(Ak) З s( raOID= OID)(Am) = s( raOID= OID)(Ak З Am),
-для декартова произведения
s( raOID= OID)(Ak) ґ s( raOID= OID)(Am) = s( raOID= OID)(Ak ><( raOID) Am),
-для вычитания
s( raOID= OID)(Ak) - s( raOID= OID)(Am) = s( raOID= OID)(Ak - Am),
-для проекции
p(rai) (s( raOID= OID)Ak) ) = s( raOID= OID)( p(rai) (Ak) ),
-для выборки
s(q)( s( raOID= OID)(Ak)) = s( raOID= OID)( s(q)(Ak) ), где q - предикат ,
-для соединения
s( raOID= OID)(Ak) ><F s( raOID= OID)(Am) = s( raOID= OID)(Ak ><(raOID and F) Am), где F – предикат,
-для деления
s( raOID= OID)(Ak) ё s( raOID= OID)(Am) = s( raOID= OID)(Ak ё Am).
Исходя из этого, можно утверждать, что для любого выражения E (уровень представления данных) найдется такое выражение E' (уровень хранения данных), что
oi.E(oa1, … , oan) OєR' s( raOID= OIDi)( E' (A1, … , An)) <15>
Рассмотрим объединение результатов применение оператора E к объектам из множества gC = {o1 , … ,ok} , gC Н С
o1.E(oa1, … , oan) И … И ok.E(oa1, … , oan) OєR'
s( raOID= OID1)( E' (A1, … , An)) И … И s( raOID= OIDk) ( E' (A1, … , An)) <16>
из чего следует, что
o1.E(oa1, … , oan) И … И ok.E(oa1, … , oan) OєR' s(raOID О {OID1, … , OIDk}) ( E' (A1, … , An)) <17>
Это позволяет утверждать, что реляционный оператор E применим и к множеству gC объектов класса С
gC.E(oa1, … , oan). <18>
Рассмотрим класс C ={o1 , … ,om} со схемой (oa1:R1, …, oan:Rn) целиком. Поскольку речь идет о всех объектах, входящих в класс, можно утверждать, что множество их идентификаторов {OID1, … , OIDm} равно множеству p(raOID) Ai для любого атрибута oai класса C ( Ai = s( raOID= OIDi)(R'), где R' = rstorage(oai), oai О Schema(С). Исходя из этого, можно показать, что
С.E(oa1, … , oan) OєR' E' (A1, … , An) <19>
Таким образом, предлагаемый подход допускает использование основанных на реляционной алгебре групповых операций, которые могут применяться к множествам объектов одного класса. Важнейшим следствием этого является то, что классы можно рассматривать как интенсиональные множества [1] объектов, причем принадлежность объектов к этим множествам однозначно определяется уже в момент создания объекта.
Это свойство важно по нескольким причинам. Очевидно, что оно делает необязательным использование разного рода коллекций, наборов и т.п. объектов, предназначенных для явного (т.е. требующего каких-либо действий со стороны программиста) задания множеств объектов, а также итераторов, служащих для последовательного просмотра этих множеств. Не столь очевиден, но ничуть не менее важен тот факт, что ссылки перестают быть единственным способом доступа к данным, хранящимся в объекте.
Последнее утверждение требует некоторого разъяснения. В традиционных объектных системах единственным средством доступа к данным, представленным в виде объектов данных, является использование ссылки на эти объекты - такой способ доступа называется навигационным. Как только утеряна ссылка, то утерян и объект. Система хранения данных, основанная на этом принципе, должна хранить не только объекты, но и (в том или ином виде) ссылки на эти объекты, с момента их создания до момента уничтожения. Поскольку такие ссылки (в отличии от ссылок, описывающих связи между объектами моделируемой предметной области) не несут какой-либо полезной информации, такую систему охарактеризовать как избыточную, и, как следствие, более сложную в управлении и использовании.
Предлагаемая альтернатива основана на том, что на уровне хранения информация об объектных идентификаторах существует точно в таком же виде, как и информация о собственных значениях этих объектов, а именно в виде явно заданных значений атрибутов кортежей отношений. В самом деле, любое отношения Ai ( Ai = ( s( raOID= OIDi) (R'), где R' = rstorage(oa)) входящее в состав выражения E' (…,Ai ,…) содержит атрибут raOID определенный на домене DOID и, следовательно, указанный атрибут может являться атрибутом отношения, являющегося результатом вычисление выражения E'. Рассмотрим оператор E' (A1, … , An), результатом которой является отношение calcR' со схемой {… , raOID : DOID, …}. Поскольку значения атрибута raOID любого из исходных отношений Ai ограничены классом C, в котором определен атрибут ai, а также с учетом взаимно-однозначного соответствия OID « O, можно предполагать, что результатом соответствующей ей на уровне представления операции E(С) будет являться отношение calcR со схемой {… , rao : C, …}.
Это позволяет утверждать, что на уровне представления возможна такая операция над классом, что ее результатом будет подмножество удовлетворяющих определенному условию объектов этого класса, или значение (значение отношения), содержащее информацию об объектах из этого подмножества. Таким образом, в предлагаемом подходе вместе с навигацией по ссылкам возможен и ненавигационный доступ к объектам и к данным, хранящихся в этих объектах.
Примером может служить запрос, который будет возвращать количество товара, отгруженного сотрудником сегодня
SELECT Sum(ShipmetItems.Pieces)
FROM cShipment
WHERE cShipment.Date = Today() <П.1>
Групповые операции над ссылками.
Поскольку отношение Rref'(см. раздел "Ссылки") содержит значения всех определенных на реляционном домене Rref атрибутов всех существующих в системе объектов, можно утверждать, что это отношение R' содержит все пары (OIDi OIDref) описываемые ссылкой oa.raref. Это позволяет говорить о возможности групповых операций над ссылками. Рассмотрим множество gс = (o1 , … ,on) объектов класса c, содержащего атрибут oa определенный на ранее описанном реляционном домене Rref. Можно говорить о том, что на уровне представления данных возможна операция
gref = p(raref)(gc.oa.raref) <20>
которая возвращает множество объектов gref, на которые ссылаются объекты, входящие в множество gc. На уровне хранения она будет реализовываться следующим образом
p(raref)(gc.oa.raref) OєR p(raref) ( s(raOID О {OID1, … ,OIDn}, raoa = oa)(R')) , где R' = rstorage(oa) <21>
Так же возможна операция, разрешающая обратную ссылку. Например, для объекта oref можно найти множество gbackref объектов класса c, которые ссылаются на него по ссылке oa.raref:
gbackref = p(с) (s(raref = oref)(с.oa.raref)) <22>
На уровне хранения данной операции соответствует следующее выражение:
p(с) (s(raref = oref)(с.oa.raref)) OєR p(raOID) ( s(raref = OIDrefi, raoa = oa)(R')), где R' = rstorage(oa) <23>
Примером может служить запрос, который будет возвращать количество товара, отгруженного сотрудником с именем Вася Петров
SELECT Sum(ShipmetItems.Pieces)
FROM cShipment
WHERE cShipment.Staff.StaffName = ' Вася Петров ' <П.2>
Вычисляемые атрибуты объектов. Инкапсуляция.
Рассматривая атрибут oa объекта oi, до сих пор мы предполагали, что на уровне хранения он представлен как подмножество кортежей отношения R', oi.oa OєR' s(raOID= OIDi, raoa = oa) (R') где R' = rstorage(oa). Будем называть такой атрибут хранимым. Однако возможен и другой случай, когда значение атрибута объекта вычисляется исходя из значений других атрибутов данного объекта. Будем называть такие атрибуты вычисляемыми.
Рассмотрим реляционный оператор Ea
R1 = Ea( R2, … , Rn),
где Ri – отношения, являющиеся реляционными доменами (rdom), на которых определены атрибуты объектов класса С. Применим оператор E к объекту oi класса С и рассмотрим выражение
oi. oa1 = oi.E(oa2, … , oan),
которое, исходя из значений атрибутов oa2, … , oan, вычисляет значение атрибута a1.
Применяя уже использованные преобразования, можно показать, что при переходе на уровень хранения это выражение может быть представлено как
o. oa1 = oi.E(oa2, … , oan) OєR' s(raOID= OIDi)( E'a (A2, … , An)) ґ {a1} <24>
, где {a1} - 1-арное отношение, единственный кортеж которого содержит имя вычисляемого атрибута { a1 }. Рассмотрим класс C и значение C.a1 = {o1. oa1 И … И ok.a1}. Можно показать, что
С. oa1 OєR' A1 , A1 = E'a (A2, … , An) ґ {a1} <25>
Выражение Ea , вычисляющее значение атрибута, должно входить в метаданные, описывающие структуру объекта. Таким образом, схема S содержащего вычисляемые атрибуты объекта класса С (S = Schema(C) ), будет выглядеть следующим образом:
S = {oa1:R1:Ea (oa2, … , oan), oa2:R2,…, oan:Rn} <26>
Интересно то, что, благодаря замкнутости реляционной алгебры (результатом любого алгебраического выражения над множеством отношений является отношение), вычисляемые атрибуты могут являться атрибутами в реляционных операциях над объектами наравне с хранимыми. Корректность выражения
calcri =С.E(oa1, … , oan) OєR' E' (A1 , … , An) <27>
зависит исключительно от типов (rdom) использующихся в ней атрибутов ai, и не зависит от того, является эти атрибуты хранимыми или вычисляемыми. Оператор Е может быть определен на основании схемы publicS = {oa1:R1, oa2:R2,…, oan:Rn}, которую можно рассматривать как спецификацию схемы объектов класса С. Информация же об ассоциированных с атрибутами операторах Еа, служащих для вычисления значений этих атрибутов, не является необходимой для использования объектов класса С (естественно, речь идет об использовании в операциях, основанных на реляционной алгебре), и, фактически, описывает некоторую реализацию схемы объектов класса . Это позволяет утверждать, что предлагаемый подход позволяет реализовать принцип инкапсуляции [4,1] - один из основных принципов объектно-ориентированного программирования, предполагающий разделения спецификации и реализации объекта.
Еще одним важным принципом, составляющим объектно-ориентированную парадигму, является принцип наследования [4], позволяющий определять новые классы на основе уже существующих. Отношение между классами, возникающее в процессе наследования, описывают существующую между ними связь "обобщение-специализация", причем класс-наследник является специализацией родительского класса, который, в свою очередь, обобщает все свои классы-наследники.
Рассмотрим класс С со спецификацией publicSC = {oa1:R1, oa2:R2,…, oan:Rn}. Предположим, что для этого класса определен реляционный оператор E
С.E(oa1, … , oan)
Рассмотрим класс Сi, являющийся наследником класса C. Спецификация класса Сi определяется как publicSCi = SC И {oan+1:Rn+1,…, oap:Rp } = {oa1:R1, oa2:R2,…, oan:Rn, oan+1:Rn+1,…, oap:Rp }. Поскольку объекты класса Ci содержат те же атрибуты, определенные на тех же реляционных доменах (rdom), что и в объекты класса С, то можно утверждать, что оператор Е применим и к объектам любых классов Ci являющихся наследниками класса C. Это позволяет рассматривать объекты классов-наследников как объекты родительского класса С.
В свете этого имеет смысл более подробно рассмотреть отношения, существующих между множеством O объектов и множеством C классов. Можно выделить два типа отношений. Первое, традиционно обозначаемое как отношение ISA, характеризуется фразой "объект oi является объектом класса C". Эта связь учитывает существующую между классами связь "обобщение-специализация", которая определяет иерархию наследования. Отношение ISA описывает связь типа "многие ко многим" – один класс может содержать множество объектов и, поскольку объекты класса-наследника считаются объектами родительского класса, одному объекту может соответствовать несколько классов. Если объект oi связан с классом C связью ISA, можно утверждать, что спецификация этого объекта содержит атрибуты, определенные в спецификации класса, ISA (oi,C) => publicSchema(C) Н publicoSchema (oi)
Второе отношение, которое в дальнейшем мы будем обозначать как отношение OFA, описывает связь, характеризующуюся фразой "объект oi создан как объект класса C". Эта связь не учитывает наследования и является связью типа "многие к одному", из чего следует, что отношение OFA является функциональным, O –OFA-> C. Для объектов и связанных с ними связью OFA классов существует точное соответствие схемы объекта и схемы класса, OFA (oi,C) => oSchema (oi) = Schema(C).Обратное отношение OFA-1 ,для каждого класса C будет формировать множество объектов DC, созданных как объекты класса C, DC = OFA-1(C). Заметим, что множества объектов DC являются непересекающимися DCi З DCi = Ж если Сi № Сj.
Рассмотрим множество IC0
классов Сi содержащий атрибут
oa, oa О publicSchema
(Ci). Эти классы образуют иерархию
наследования, где и один из них - класс С0
, в котором атрибут oa объявлен впервые
- является родительским для остальных
классов Ci (i > 0), наследующих этот
атрибут. Множество объектов, входящих в
класс С0, является объединением всех
объектов, созданных как объекты классов,
входящих в иерархию IC0,
C0 = И DCi
, где Ci О IC0.
Таким образом, значение C0.oa,
представляющее собой объединение значений
атрибутов oa объектов, принадлежащих
классу C0, является объединением
значений DCi
. oa,
представляющих собой объединения значений
атрибутов oa объектов, созданных как
объекты класса, входящих в иерархию I, С0.oa
=
DCi
. oa, где DCi
. oa =
o.oa.
Значение вычисляемого атрибута oa определяется оператором Ea, ассоциированным с этой переменной. Поскольку этот оператор определен только в реализации схемы объектов класса C, можно предположить, что он может переопределяться в процессе наследования. Отметим, что переопределение, подразумевающее изменение реализации схемы объектов при неизменной спецификации, является одним из способов создания полиморфных[4] систем.
Рассмотрим класс С0 со схемой SC0 = {oa1: R1: C0Ea , oa2:R2,…, oan:Rn}. Атрибут oa1 вычисляется исходя из значений других атрибутов выражением C0Ea, oa1 = C0Ea (oa2, … , oan). Предположим, что для этого класса определен реляционный оператор E
С0.E(oa1, … , oan)
Рассмотрим иерархию IC0 и входящие в нее классы Сi (i > 0), которые являются наследником класса C0 и имеют схему SCi = { oa1:R1:CiEa, oa2:R2,…, oan:Rn, oa2:R2,…, oan:Rn, oan+1:Rn+1,…, oap:Rp }. В процессе наследования, выражение, вычисляющее значение атрибута oa1, может быть переопределено, причем, возможно, оно будет учитывать значения атрибутов oan+1,…, oap, отсутствующих в родительском класса C0
oa1 = CiEa (oa2, … , oap).
Рассмотрим значение С0.oa1 представляющее собой объединение значений атрибутов oa1 объектов класса С0, o О C0
С0.oa1 =
DCi .
oa1 , где DCi.oa
=
o.oa.
<28>
Как мы ранее показывали, значение переопределяемого атрибута oa объекта ok любого из классов Ci на уровне хранения будет вычисляться следующим выражением
ok.oa1 = ok. CiE(oa2, … , oa n, …) OєR' s(raOID= OIDk) (CiE'a (A2, … , An, … )) ґ {a1} <29>
Выражение, объединяющее значения атрибутов oa всех объектов, созданных как объекты класса Сi, будет выглядеть как
DCi oa1 = DCi . CiE(oa2, … , oa n, …) OєR' s(raOID OFA Ci )( CiE'a (A2, … , A n, …)) ґ {a1} <30>
(реализация предикатов OFA и ISA на уровне хранения будет рассмотрена далее – см. "Связь данных и метаданных"). Следовательно, значение С0.oa1 представляющее собой объединение значений атрибутов oa1 полиморфных объектов класса С0, на уровне хранения будет вычисляться как
C0.a1 OєR'
(
s(raOID
OFA Ci )( CiE'a
(A2, … , A n, …)) ) ґ
{a1}
<31>
Случай, когда переопределяемый атрибут a1 в процессе наследования становиться или, наоборот, перестает быть хранимым, выглядит немного сложнее:
C0.a1 OєR'
( (
s(raOID
OFA Ci )( CiE'a
(A2, … , A n, …)) ) ґ
{a1} ) И A1
<32>
Отметим, что в любом случае вычисляющее выражение не выходит за рамки реляционной алгебры.
Возможность переопределение атрибутов заслуживает внимания, поскольку позволяет создавать гибкие расширяемые системы. Рассмотрим групповой реляционный оператор С0.E(oa1, … , oan), который может применяться к множеству объектов класса C0. Принимая во внимание тот факт, что он определен на основании спецификации схемы объектов этого класса, можно утверждать, что его можно применять к объектам, принадлежащим любым классам Ci, наследующим класс С0, в том числе и классам с переопределенными атрибутами.
Вернемся к примеру. Предположим, что наряду с отгрузками склад стал заниматься продажами товар. В связи с этим создадим класс cSales, объекты которого описывают продажи. Поскольку продажа подразумевает отгрузку, естественно предполагать, что этот класс должен рассматриваться как наследник класса cShipment. В процессе проектирования схемы данных было выделено свойство(rdom) pSalesGoods, значения которого содержат информацию о количестве и цене продаваемого товара.
PROPERTY pSaledGoods{
Good As cGoods PRIMARY KEY;Price As DOUBLE;Pieces AS INT;
}
С учетом всего сказанного, схема класса cSales должна содержать выражение, переопределяющее описанный в классе cShipment аргумент ShipmentItems таким образом, что бы он вычислялся на основании данных о продажах, хранящихся в атрибуте, определенным на свойстве pSaledGoods
CLASS cSales EXTENDS cShipment {
…;SalesItems AS pSaledItems; //Теперь данные хранятся здесь.REDEFINE ShipmentItems //Этот аргумент вычисляется на основании данных… AS SELECT Good, Pieces FROM SalesItems; // …хранящихся в SalesItems.…;
} <П.4>
Поскольку такая схема реализует спецификацию класса cShipment, можно утверждать, что объекты класса cSales являются один из вариантов объектов полиморфного класса cShipment. Особо отметим, что созданные ранее (см. <П.1> и <П.2>) запросы, возвращающие информацию об отгруженном товаре, останутся корректными, и по-прежнему будут возвращать информацию обо всем отгруженном товаре, включая информацию о товаре, отгруженном в рамках продаж.
Схема данных, описывающая предметную область в терминах классов и свойств, определяет существование множества C классов, множества oa их атрибутов, множества R отношений (свойств), являющихся реляционными доменами этих атрибутов, а также ряда отношений между указанными множествами. Совокупность перечисленных множеств и отношений представляет собой метаданные (данные о данных), позволяющие представить данные, хранящиеся в терминальном механизме хранения данных (реляционное ОЗУ), в терминах используемой абстракции (свойства и классы).
Предполагая, что единственно возможный терминальный механизм хранения данных основан на реляционной модели данных, можно утверждать, что и сами метаданные должны храниться в виде набора отношений, совокупность которых образует каталог системы. Таким образом, перманентное реляционное ОЗУ используется для совместного хранения данных и метаданных,
Следующие отношения образуют структуру каталога (первый столбец содержит имя атрибута, второй – накладываемые на него ограничения):
1)RDOMENSs - перечисляет существующие реляционные домены - отношения из множества R (rdom)
|
IDR |
Primary key |
Уникальный идентификатор реляционного домена. |
Для любого реляционного домена R, отношение RDOMENSs должно содержать единственный кортеж, ключевое поле IDR которого содержит значение idR , идентифицирующее этот домен.
Ограничившись отношением, перечисляющим реляционные домены R, мы не будем останавливаться на подробном описании их структуры. Отметим, что это описание однозначно соответствует хранящемуся в каталоге базовой реляционной системы хранения данных описанию существующего на уровне хранения отношения R'.
2) CLASSES - перечисляет существующие классы.
|
IDC |
Primary key |
Уникальный идентификатор класса (например имя класса). |
Для любого класса С, отношение CLASSES должно содержать единственный кортеж, поле IDC которого содержит значение idC , идентифицирующее этот класс.
3) ISA – определяет отношение ISA, существующее между классами (множествами объектов)
|
IDC |
Primary key, Foreign key on CLASSES.IDC |
Идентификатор класса. |
|
ISAС |
Primary key, Foreign key on CLASSES.IDC |
Идентификатор класса с которым класс IDC связан отношением ISA. |
Это отношение содержит информацию о классах, связанных отношением ISA. Например для класса С'' , являющегося наследником С', который в свою очередь наследует базовый класс C, отношение ISA должно содержать кортежи {idC'', idC''}(класс С'' является сам собой), {idC'', idC'} (класс С'' является наследником класса C'), и {idC'', idC} (класс С'' является наследником базового класса C). Таким образом, отношение ISA содержит полную информацию о иерархии наследования. Применяя к нему оператор выборки, для любого класса С' можно найти все его классы наследники, или все классы, для которых он является наследником.
4) ATTRspecification –перечисляет существующие атрибуты, определяет, в каких классах они впервые объявлены, определяет реляционный домен (rdom) каждого атрибута
|
o a |
Primary key |
Уникальный идентификатор объектного атрибута (например имя атрибута). |
|
IDC |
Foreign key on CLASSES.IDC |
Идентификатор класса, где этот атрибут впервые объявлен. |
|
IDR |
Уникальный идентификатор отношения, являющегося реляционным доменом (rdom) этого атрибута. |
Если в классе C впервые объявлен атрибут oai, определенный на реляционном домене R, то это отношение будет содержать кортеж { oai, idC, idR}.
5) ATTRrealization – описывает реализацию атрибутов в классах и в наследуемых классах, содержит данные, которые могут быть переопределены в процессе наследования
|
o a |
Primary key, Foreign key on ATTRspecification.oa |
Иденитфиткатор объектного атрибута. |
|
IDC |
Primary key, Foreign key on CLASSES.IDC |
Идентификатор класса, содержащего этот атрибут (из-за наследования таких классов может быть много). |
|
Expr |
Выражение, вычисляющее значение атрибута (может переопределяться в процессе наследования классов, отсутствует для хранимых атрибутов). |
Если атрибут oai базового класса С переопределен в классе-наследнике C', то это отношение должно содержать кортежи { oai, idC, CE} и { oai, idC', C'E}, где CE и C'E –определенные в классах C и C' выражения, вычисляющие значение атрибута oai. Для хранимых атрибутов выражение CE может отсутствовать.
Еще раз отметим, что на уровне хранения данные и метаданные существуют совместно и представлены в одном и том же виде, а именно как множество значений отношений. Этот факт позволяет использовать присущие реляционным системам механизмы контроля целостности данных для поддержки взаимного соответствия между данными и метаданными.
Описывая стержневое отношение R'0, существующее на уровне хранения, мы сказали, что в него могут входить атрибуты, характеризующие объекты данных, входящие в состав системы. Важнейшей характеристикой всех без исключения объектов данных является класс этих объектов, поэтому в стержневое отношение должно входить поле IDC связанное с первичным ключом отношения CLASSES. Таким образом, каждому объекту данных ставиться в соответствие схема данных класса, который указан в выражении, которым этот объект был создан. Система должна контролировать, что структура объекта на протяжении всей его соответствует схеме данных, определенной для объектов этого класса.
Таким образом, схема стержневого отношения должна выглядеть следующим образом:
R'0
|
r aOID |
Primary key |
|
|
IDC |
Foreign key on CLASSES.IDC |
Рассмотрим выражение
new cShipment;
создающее объект класса cShipment. В результате его обработки система должна добавить в стержневое отношение новый кортеж, поле которого будет содержать уникальный идентификатор созданного объекта, а поле IDC будет определять, что этому объекту соответствует схема класса cShipment. Дальнейшие действия, сводящиеся к операциям над кортежами отношений R', содержащими данные об объектах класса cShipment, должны выполняться в соответствии с этой схемой.
Еще раз вернемся к тому факту, что выражение, создающее объект, может не возвращать указатель на него. Предположим, что в классе cShipment определено инициализирующее выражение (конструктор) принимающее в качестве параметра номер отгрузки. Тогда команда
new cShipment(123);
создаст объект данных описывающих отгрузку под номером 123. В дальнейшем мы можем обращаться к этому объекту как к экземпляру класса cShipment. Например, выражение, изменяющее дату отгрузки, может выглядеть следующим образом.
UPDATE cShipment SET cShipment.SDate = "…" WHERE cShipment.NoS = 123
Отметим следующее. Поскольку для каждого объекта данных на всем протяжении его жизни в стержневом отношении хранится информация о том, что этот объект создан как объект определенного класса, то можно утверждать, что стержневое отношение R'0 и отношение OFA суть одно и тоже. Введенный ранее предикат OFA реализуется на уровне хранения простой выборкой кортежей этого отношения по атрибуту IDC. Например следующая часть выражение <30> s(raOID OFA Ci )( CiE'a (A2, … , A n, …)) будет реализована как
s(IDC = Ci )( R'0 ><(raOID) ( CiE'a (A2, … , A n, …)) ) <30'>
Релизация предиката ISA немногим более сложна. В этом случае мы должны использовать отношение ISA существующее в каталоге системы.
s(raOID ISA Ci )( E'a ( … , A n, …)) = s(ISAIDC = Ci) (ISA ><IDC ( R'0 ><(raOID) ( CiE'a (A2, … , A n, …)) ) )
Должен существовать и обратный контроль. Речь идет о случае, когда в процессе эксплуатации системы меняется схема данных. В этом случае должен существовать механизм, контролирующий, насколько вносимые изменения соответствуют уже существующим данным и позволяющий, при необходимости, преобразовывать уже существующие данные. Возможны два случая
1) Изменение схемы свойства R, определенного на уровне представления, сводится к изменению схемы отношения R', которое существует на уровне хранения.
2) Изменения схемы класса (например: добавление или удаление атрибутов класса, изменение вычисляющих выражений и т.п.), на уровне хранения сводится к кортежным операциям над отношениями ISA, ATTRspecification и ATTRrealisation, входящим в каталог системы.
Во втором случае, для контроля корректности изменения схемы класса, можно использовать связь между атрибутом raoa, каждого из отношений R'i, и атрибутом oa отношения ATTRspecification, являющегося первичным ключом этого отношения. Существование такой связи позволяет гарантировать, что для всех кортежей всех отношений R'i в каталоге существуют ассоциированные с ними описания атрибутов, позволяющие привести хранящиеся в них данные к виду, определяемому используемой абстракцией, т.е. представить эти данные как значения атрибутов объектов данных.
Указанные связи между данными и метаданными (уровень хранения), а также связь между отношениями R'i и стержневым отношением R'0, определяют целостность объектов данных o (уровень представления), описываемых как {OID, S, oV}, где OID – уникальный идентификатор указанной переменной, S – метаданные, описывающая структуру указанной переменной, oV - сложное значение, описывающее состояние объекта.
Одно из наиболее важных свойств объектно-ориентированных систем определяется тем, что объект характеризуется не только состоянием (набор значений атрибутов) но и поведением [4], выраженным через множество методов, применимых к объекту и инкапсулированных в нем. Методы позволяют управлять состоянием объекта и, следовательно, системы в которую он входит. Таким образом, системы, реализующие объектно-ориентированный подход, объединяют структурные и поведенческие аспекты описания и использования данных.
Предлагаемый подход не содержит каких-либо принципиальных ограничений на определение и использование методов, которые, подобно атрибутам, могут наследоваться и переопределяться. Если предположить, что уровень хранения основан на существующих реляционных СУБД, то метод класса может быть реализован в виде ассоциированной с классом хранимой процедуры, получающей в качестве параметра объектный идентификатор объекта, для которого он вызван. Отметим, что этот идентификатор может быть получен в результате выполнения групповой операции над классом (см. "Групповые операции. Ненавигационный доступ к данным"). Таким образом, возможны вызовы методов из непроцедурных языков высокого уровня. Например, следующее выражение вызовет метод DoShip для объекта класса cShipment, который содержит данные об отгрузке с номер 123
EXEC cShipment.DoShip() WHERE cShipment.NoS = 123.
Можно предположить, что метод может быть вызван и для группы объектов.
EXEC cShippment.DoShip() WHERE cShipment.sDate = Today() <П.5>
Естественно, что возможен вариант, когда к методу неприменимо преобразование, описанное в главе "Групповые операции. Ненавигационный доступ к данным" (например, это будет верно для методов, выполняющих покортежную обработку атрибутов объекта). В этом случае выражение <П.5> может быть реализовано только в виде итератора, последовательно обращающегося к каждому из объектов входящих в обрабатываемую группу. Однако сама группа будет формироваться в результате групповой операции над классом.
В заключение отметим, что для хранения методов можно использовать уже описанный каталог системы, где организация описывающих их метаданных не будет принципиально отличаться от организации метаданных, описывающих вычисляемые атрибуты объектов.
В статье предлагается подход, позволяющий создать объектно–ориентированную информационную систему на основе терминального механизма хранения данных, описываемого реляционной моделью. Вводятся правила, позволяющие преобразовать схему данных, возникшую в результате нормализации, к объектной схеме данных. Исследуются свойства, которыми может обладать система, основанная на предлагаемом подходе. Показано, что такая система
Конечно, в небольшой статье невозможно предусмотреть все вопросы, которые могут возникнуть при знакомстве c предложенным подходом. Однако предлагаемые решения могут быть вполне достаточными для практической реализации в виде системы, которая может представлять определенный интерес для широкого круга пользователей.
Автор благодарит участников форума "Проектирование БД", расположенного на сайте www.sql.ru, принявших активное участие в обсуждении статьи, за их ценные замечание и предложения.
1) Определение "кибернетические" в данном случае означает "управляемые". При определенных внешних воздействиях (в ответ на определенную команду) такая система определенным образом меняет свое состояние. (назад к тексту)
2) Фактически, терминальная система хранения данных предопределяет существующий в языках программирования набор "базовых" типов (например, целочисленный тип). Она представляет собой среду существование переменных базовых типов и реализует операции над этими переменными. Говоря про "базовые типы", нельзя не обратить внимание на то, что это понятие обычно ассоциируется с набором простейших типов, реализуемых аппаратной частью компьютера (например, byte, char, int, float и т.п.). Однако отметим, что терминальный механизм не обязательно реализуется аппаратно (в качестве примера можно привести виртуальную Java-машину). Можно предположить, что базовые типы могут быть произвольно сложными - при условии, что эта сложность полностью реализована на уровне терминальной системы. (назад к тексту)
3) Единственным типом, реализуемым реляционными системами хранения данных, является тип "отношение". Переменными этого типа являются переменные отношения "relvar" ( или, в терминах SQL-систем, таблицы) служащие для хранения значений отношений "relval". Реляционная БД - это БД в которой все данные представлены в виде набора значений отношений [9]. (назад к тексту)
4) С учетом сказанного схема, описывающая потоки команд и данных, еще более усложнится и будет выглядеть приблизительно так. (назад к тексту)

Евгений Григорьев (С) 2003. Некоторые идеи, изложенные в статье, имеют патентную защиту.
|
CITForum © 1997–2025