Функциональность отношений

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

    В объектной же парадигме для реализации связи объектов используют их идентификаторы. Причем, если связи объектов придать строгую симметричную форму: в виде пары прямая | обратная ссылка, то это позволяет практически полностью заменить Select естественной навигацией по ссылкам. Но что не менее важно, симметричная форма делает связь объектов полноправным и самостоятельным элементом логической структуры базы данных, обладающим собственным поведением и функциональной зависимостью от других действующих связей.

    Настоящая статья посвящена рассмотрению самых различных поведенческих аспектов связи объектов, реализация которых позволяет интегрировать значительную часть бизнес-логики приложения непосредственно в логическую структуру базы данных, тем самым избавляя разработчика от рутины кодирования.

    (Автор позволил себе отклониться от общепринятых терминологических канонов, желая придать изложению чуть больше образности).

    С информационной точки зрения связь двух объектов следует понимать исключительно как взаимный обмен идентификаторами, по принципу – «я тебя вижу», и не более того. При этом сам объект – это экземпляр класса данных, а связь объектов класса – практическая реализация правил, устанавливаемых декларацией отношения классов — экземпляра одной из четырех фундаментальных абстрактных сущностей, используемых для моделирования предметной области.

    Каждый из связываемых отношением классов получает в свое владение ссылочный атрибут, типизированный оппозитным классом отношения, значением которого в объекте класса становится идентификатор объекта оппозитного класса. Отношение классов не только устанавливает правила связи объектов, но и служит естественным контекстом (транспортом и условием) для организации взаимодействия атрибутов, локализованных в разных классах.

    Типы отношений


    Тип отношения устанавливает меру количественного взаимодействия объектов, производных от связанных отношением классов. Как известно, вариантов этой меры всего три: один-к-одному, многие-к-одному, и многие-ко-многим.

    Отношение типа многие-к-одному, которое удобно именовать множественным отношением, имеет явно выраженный вектор причинности: первичным получателем значения (ссылки) всегда является ссылочный атрибут на стороне ”многие”, а значением атрибута на стороне ”один” будет производный список значений (ссылок). Отсюда и возникает часто используемое далее терминологическое деление атрибутов этого отношения на атрибут прямой ссылки и атрибут обратной ссылки.

    В полностью симметричном отношении один-к-одному (оно же – унитарное отношение), каждый из равноправных ссылочных атрибутов может выступить в качестве инициатора создания связи объектов, и быть первичным получателем значения. Деление на атрибуты прямой и обратной ссылки в таком отношении носит чисто ситуационный характер. И это при том, что один из них получит свое значение как следствие присвоение значения оппозитному атрибуту.

    Понятийный смысл отношения многие-ко-многим весьма неоднозначен, что делает его предметом отдельного рассмотрения.

    Графическое представление множественного и унитарного отношений, которое далее будет использовано в иллюстрациях, выглядит как-то так:

    Такая нотация используется потому, что графический образ стрелки интуитивно ассоциируется как с образом вектора зависимости, так и с образом спискового атрибута обратной ссылки. Маркировка ссылочного атрибута типом и наименованием не является обязательным элементом изображения. Ссылочный атрибут типизирован оппозитным классом отношения, и, соответственно, заимствует наименование этого класса.

    Ссылочный соединитель


    Симметрия связи объектов обусловлена причинно-следственной зависимостью значений ссылочных атрибутов связываемых объектов. Как и всякая другая зависимость, она реализуется соединителем, который далее будем называть ссылочным соединителем. Ссылочный соединитель априори активен, что обеспечивает перманентную логическую согласованность и целостность ссылочных значений. В своей работе ссылочный соединитель использует, помимо собственно ссылочных атрибутов, также и служебные атрибуты Own и Del. Декларация соединителя множественного отношения выглядит так:
    Служебный атрибут Own типизирован собственным классом, и в объекте класса хранит собственный идентификатор этого объекта (IDO). Именно этот атрибут используется всеми типами отношений в качестве источника значения, передаваемого соединителем отношения однотипному с ним атрибуту обратной ссылки.

    Служебный атрибут Del используется соединителем отношения в качестве lock-контекста. При логическом удалении объекта класса A, его атрибут Del будет инициализирован, что породит вызов метода Unset в адрес базового сокета соединителя, что в свою очередь приведет к вызову в адрес атрибута B.{A} метода Set с «пустым» значением и ключом, и в результате соответствующая запись будет изъята из списка обратных ссылок B.{A}.

    В качестве атрибута Key (key-контекст соединителя) по умолчанию выступает базовый атрибут класса. Значение этого атрибута используется соединителем как ключ, в пару к передаваемому значению — IDO атрибута Own. Получающий эту пару атрибут обратной ссылки B.{A} обладает простым функционалом списка, который непосредственно и формирует сам список обратных ссылок.

    Ну а собственно атрибут прямой ссылки A.[B] является всего лишь ref-контекстом, который предоставляет соединителю идентификатор IDO целевого объекта. Когда в процессе реализации ссылки атрибут A.[B] получит хранимое значение, то он вызывает в адрес базового сокета соединителя метод Reset, что в свою очередь приведет к вызову в адрес атрибута B.{A} метода Set с IDO объекта и ключом, и в результате в список обратных ссылок B.{A} будет добавлена новая запись. Далее, любое последующее изменение значений атрибутов Key и прямой ссылки A.[B] будет сопровождаться последовательными вызовами Unset и Reset с соответствующими изменениями в списке(ах) обратных ссылок.

    В унитарном отношении очевидным образом не используется key-контекст, но зато присутствуют два ссылочных соединителя, которыми обеспечивается зеркальная симметрия реализации:
    При пристальном взгляде на представленную декларацию может показаться, что имеются все предпосылки для зацикливания процесса присвоения ссылочного значения, но это не так. Метод Set не порождает производные рекурсивные вызовы, если значение, полученное им извне, эквивалентно уже имеющемуся в наличии.

    Создание отношения


    Помимо двух ссылочных атрибутов, в образовании отношения задействован как минимум один соединитель, объединяющий набор сокетов с соответствующим образом установленными флагами. Хочется подчеркнуть, что весь этот объем деклараций скрыт за фасадом визуального конструктора модели данных, использующего предопределенные методы и формы представления абстрактного мета-отношения для создания его экземпляров. Все, что требуется конструктору для создания экземпляра отношения – это его тип и дескрипторы связываемых классов.

    Также хочется лишний раз подчеркнуть: ни отношение классов, ни соединитель атрибутов, не являются сущностями модели данных, и никак ею не интерпретируются. Модель данных оперирует только классами, атрибутами и сокетами. Отношение и соединитель являются сущностями модели приложения, которая в свою очередь является представлением (формой представления) модели данных.

    Мощность отношения


    Рассмотрим такую операцию, как передача Товара со Склада на Склад: в объекте Передаточная накладная необходимо адресовать сразу два объекта Склад. Реализуется такая потребность простым увеличением мощности отношения, с заменой атомарной формы хранения производных значений ссылочного атрибута A.[B] на перечислимую (массив).
    Увеличивая мощность множественного отношения (кратность ссылки), конструктор модели создаст у атрибута прямой ссылки дополнительный элемент, и к нему еще один соединитель отношения, аналогичный уже существующему, который использует новый элемент в качестве источника адресного указателя (ref-контекст). Обратим внимание — увеличение мощности не повлияло на декларации атрибута обратной ссылки B.{A}, за исключением добавления еще одного входящего сокета. (На этом и последующих рисунках показаны только необходимые по смыслу контексты).

    Аналогичным образом реализуется увеличение мощности унитарного отношения.
    Так как этот тип отношения обладает дополнительной внутренней симметрией, то количество элементов у ссылочных атрибутов на обеих сторонах отношения всегда будет одинаковым.

    В свою очередь, атрибут обратной ссылки множественного отношения может обеспечить существование более чем одного списка. По умолчанию, первый (основной) список использует в качестве ключа базовый атрибут класса (для Накладной это будет атрибут Date). Предположим, что для каких либо целей требуется еще один список с другим порядком сортировки, например, по сумме накладной Total. Создавая декларацию нового списка, конструктор отношения создаст у атрибута обратной ссылки дополнительный элемент (A2), а также дополнительный ссылочный соединитель. Новый соединитель аналогичен первичному, но в качестве источника ключа использует уже не Date, а атрибут Total.
    Обратим внимание и подчеркнем: добавление нового списка не изменяет мощности отношения.

    Если в свойствах списка указать дополнительный логический контекст, то в него попадут только те записи, для которых значением контекста будет true. Такая опция будет полезна например, при ведении ”бело-серой” бухгалтерии. А так как все три контекста базового ссылочного соединителя уже использованы, то можно воспользоваться свободным lock-контекстом одного из контекстных сокетов. Например, так:

    Как видим, в отличие от ref — и key — контекстов, lock-контекст можно наращивать каскадно, создавая дополнительный логический контекст (условие) для уже существующего.

    Управление ссылочной целостностью


    Представляется очевидным, что объект, на который ссылаются, не может быть произвольным образом удален. Соответственно, в целях сохранения ссылочной целостности необходим контроль наличия актуальных внешних ссылок на объект.

    Как мы помним, объект логически удаляется при инициализации значения служебного атрибута Del. Для того, чтобы обеспечить возможностью контроля внешних ссылок, каждый атрибут обратной ссылки, при своем создании автоматически создает отдельный пассивный соединитель к атрибуту Del.
    В методе Set специализированный служебный функционал атрибута Del проверяет все входящие соединители, и как только один из них вернет true (список обратных ссылок не пуст), функционал породит исключение, прерывающее транзакцию. Но до исключения можно и не доводить. Метод Get, адресованный атрибуту Del, опросит соединители, и вернет false, если удаление объекта возможно без конфликтов.

    Существуют отношения, которые с понятийной точки зрения принято рассматривать как "родительские". Например, Накладная и ее условно "дочерние" Записи, которые могут существовать исключительно в контексте Накладной. Тут ожидается прямо противоположное поведение: объект Накладная не только может быть удален при наличии обратных ссылок от объектов Запись, но и должен также, в процессе собственного удаления, удалить все свои Записи. Требуемая реакция может быть обеспечена установкой виртуального флага Owner в свойствах отношения, после которой в модели данных будут сделаны следующие изменения:


    Во-первых, будет добавлен активный соединитель, связывающий атрибуты Del в классах Накладная и Запись, а во-вторых, сбросом флага Get будет де-активирован соединитель, связывающий Del с соответствующим списком обратных ссылок.

    Взаимная зависимость отношений


    Рассмотрим систему из трех классов, связанных множественным отношением:


    Объект класса C обладает прямыми указателями на объекты B и A, объект В – указателем на А. Так как никаких дополнительных правил и ограничений нет, то связанные взаимной ссылкой объекты C и B в самом общем случае могут непротиворечиво адресовать в том числе и разные объекты класса А.

    Слегка изменим пример, внеся в него определенную смысловую нагрузку.

    Пусть C – это класс Студент, BФакультет, AВУЗ. Представляется очевидным, что Студент числится исключительно в том учебном заведении, на Факультете которого проходит специализированное обучение. Иными словами, для Студента указатель на ВУЗ определяется через указатель на Факультет. Это правило устанавливается созданием соединителя, связывающего атрибуты прямой ссылки на класс A в классах B и C через отношение CB. Обратим внимание, связываемые атрибуты имеют одинаковый тип — класс A.


    Декларация активной связи ссылочных атрибутов стандартным соединителем автоматически обеспечит требуемую согласованность ссылочных значений C.[A] = B.[A] при любых внешних воздействиях. В самом деле:

    • при любом получении/изменении значения C.[B] соединитель будет инициирован (методами Unset/Reset) для передачи значения атрибута B.[A] в атрибут C.[A];
    • при изменении значения атрибута B.[A], новое значение будет передано всем объектам C из списка обратных ссылок B.{C};

    Декларация активной зависимости атрибутов прямой ссылки C.[A] = B.[A] порождает прямое логическое следствие:

    • при наличии у объекта C актуального значения С.[A] (например, Студент уже выбрал ВУЗ для обучения), областью определения допустимых значений атрибута C.[B] будет список обратных ссылок атрибута A.{B} (список Факультетов данного ВУЗа). Это следствие в первом своем приближении принимает форму ограничения, которое в модели данных выражается явным образом — автоматическим созданием соединителя C.[B] = A.{B}, далее именуемым back-соединителем, производного от декларации direct-соединителя C.[A] = B.[A].


    Производный back-соединитель абсолютно пассивен, он не инициируется изменением атрибута C.[A], так как соответствующие флаги (Unset/Reset) контекстного сокета выключены, и в процессе отработки внешних воздействий он участия не принимает. Этот соединитель используется в процессе организации присвоения значения ссылочному атрибуту C.[A], что будет детально рассмотрено позже. А пока обратим внимание, что адресуемый back-соединителем список обратных ссылок, если его рассматривать как источник данных, предоставляет множество однородных значений, без возможности автоматически выбрать из них единственное.

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

    Группировка по значению


    Рассмотрим пример из все тех же трех классов, но, для большей наглядности, в несколько иной интерпретации: класс A – это некоторый Журнал, Записи которого (класс C) следует группировать по календарным Дням (класс B). Каждый День в Журнале уникален по значению календарной даты Date (D). Данную уникальность обеспечивает назначенный атрибуту обратной ссылки A.{B} слегка модернизированный функционал списка, который генерирует транзакционное исключение при попытке добавить в список запись с уже существующим в списке значением ключа.

    Соединитель back также претерпел некоторые изменения: он использует в качестве key-контекста атрибут Date (D), и стал полу-активным: его контексты активны (для всех контекстных сокетов соединителя установлены флаги Unset/Reset), при сброшенном флаге Set базового сокета.


    При активных контекстных сокетах, любое изменение значений атрибутов C.[A] или C.D активирует back-соединитель, который извлечет значение C.D, и использует его как ключ при обращении к списку A.{B}, после чего полученное значение (IDO объекта B) будет присвоено целевому атрибуту. Тем самым реализуется автоматическое позиционирование (иначе — группировка) объектов класса C на объекты класса B.

    А что произойдет, если в качестве значения C.D ввести дату, для которой не существует соответствующего объекта День? В этом случае back-соединитель закономерно вернет значение NUL, и ссылка на День будет де-инициализирована.

    Стоит отметить, что изредка требуется и такое поведение, но чаще всего требуемый объект День, соответствующий введенной дате, должен быть создан автоматически. Для реализации такого поведения атрибуту C.[B] назначают функционал Autoset. Этот функционал (рассматривается ниже) при его инициации back-соединителем автоматически создаст новый объект класса B, после чего присвоит атрибуту прямой ссылки в качестве значения идентификатор созданного объекта.

    Но этого недостаточно. Для сохранения ссылочной целостности, атрибуты D и {A} нового объекта B должны автоматически получить строго определенные значения, а именно — совпадающие с текущими значениями аналогичных атрибутов объекта C. Для этих целей в соединителях B.D→C.D и B.[A]→C.[A] включается реверс передачи значения, а именно: во входящих Get-сокетах соединителя, принадлежащих атрибутам C.D и C.[A], дополнительно устанавливается флаг Set. Тогда при присвоении значения атрибуту C.[B], — транспортному контексту соединителей B.D→C.D и B.[A]→C.[A], эти соединители будут инициированы на передачу значений в объект B. Обратим внимание – приведенная на схеме декларация зависимостей обеспечивает автоматическое сохранение логической и ссылочной целостности при изменении любого из значений.

    Рассмотренный выше набор деклараций, реализующий группировку объектов по значению атрибута, создается внутренним конструктором модели в два приема. Если в некотором общем классе в свойствах атрибута обратной ссылки включить опцию уникальность, то отношение, которому принадлежит данный атрибут становится уникальным. При этом сам целевой класс ссылки теперь может выступать в качестве класса, группирующего ссылки по значению своего базового атрибута. Отношение с таким классом любого третьего класса, обладающего при этом также отношением с общим классом, приобретает опцию (в диалоге свойств), позволяющую выбрать в кортеже третьего класса атрибут, по значению которого реализуется группировка.

    Группировка по ссылкам


    Слегка модернизируем предыдущий пример: пусть место абсолютного атрибута D в классах A и С займет атрибут прямой ссылки на класс D (списку обратных ссылок в общем-то едино, что будет играть роль ключа к значению: календарная дата или идентификатор объекта IDO). И для большей наглядности изменим смысловое значение классов: класс A – это Товар, класс DСклад, класс СЗапись счета/накладной (движение Товара). Тогда смысловая нагрузка на класс B становится однозначно производной: это Товар-на-Складе. Если заменить Склад на Поставщика или Покупателя, то класс B станет Товаром-у-Поставщика/Покупателя.

    Соответствующая сделанным изменениям декларация будет выглядеть так:


    Любая Запись при получении конкретных указателей на объекты Склад и Товар автоматически получит указатель на объект Товар-на-Складе, а в случае отсутствия такового – автоматически же его создаст. Обратим внимание: связь двух классов, Товар и Склад, через третий класс (Товар-на-Складе) представляет собой вариант реализации отношения многие-ко-многим, альтернативный прямому обмену значениями двух атрибутов обратной ссылки. Причем этот вариант обладает еще и свойством уникальности. Иными словами, для каждой пары объектов Товар и Склад, связывающий их объект Товар-на-Складе существует в единственном экземпляре. Такое поведение обусловлено свойством уникальности списка обратных ссылок, для которого в качестве источника ключа используется атрибут-указатель на оппозитный класс. И совершенно неважно, в каком из двух классов (Товар или Склад) декларирована уникальность списка, – такой же список обратных ссылок (с обычным функционалом списка) в оппозитном классе будет по факту содержать уникальный набор ключей.

    Отношение многие-ко-многим


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

    Совсем иное дело, когда отношение через третий класс обладает свойством уникальности, как Товар-на-Складе из примера выше. Здесь спецификой третьего класса (класса связи) является не столько использование атрибутов отношения в качестве источников ключа, сколько его понятийная «производность» от отношения классов. Поэтому, такая уникальная (по идентификаторам) связь классов через третий класс и будет в дальнейшем рассматриваться в качестве отношения типа многие-ко-многим. Именовать же такой тип можно как уникальным отношением, так и отношением-проекцией.

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


    Что примечательно, комбинацией отношений проекции можно реализовать любую многомерную аналитику данных. В самом деле, отношением проекции можно связать любую пару классов, и в том числе уже имеющиеся в наличии классы-проекции, после чего в атрибутах всех классов-проекций организовать обобщение численных значений.

    Корреспонденция


    Увеличивая кратность отношения мы тем самым позволяем объекту одного класса адресовать два и более объекта другого класса, что в свою очередь также может рассматриваться как логический аналог рассмотренной ранее связи многие-ко-многим.


    Исходя из этого следует предположить, что у кратной формы отношения должна существовать своя проекция — уникальная форма кратного отношения, указатель на объект которой может быть получен автоматически.

    И такое уникальное отношение действительно будет создано, если в процессе диалога создания отношения-проекции в качестве целевых классов выбрать один и тот же класс. И после того, как будет создано отношение простого класса на класс-проекцию, декларация атрибутов и соединителей примет следующий вид:

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

    На что в приведенной декларации следует обратить внимание: в отличие от обычной проекции, связывающей любую пару объектов своим единственным экземпляром, в корреспонденции такая связь реализуется двумя экземплярами, по одному на каждую комбинацию указателей в элементах прямой ссылки. Для этих целей во всех взаимодействиях, включая формирование списка обратных ссылок, ссылочные указатели, выступающие как в качестве значений, так и в качестве ключей, дополняются индексом элемента, в котором размещены. Кроме того, для блокировки бессмысленной двойной адресации, ссылочному атрибуту в классе-проекции можно назначить специальный функционал, который запрещает присваивать обоим элементам одинаковое значение.

    Реализация отношения


    Существует ровно один способ реализовать отношение в объекте класса – присвоить методом Set атрибуту прямой ссылки идентификатор целевого объекта IDO. Причем соответствующий вызов может быть инициирован как извне, так и самой моделью данных. Например, атрибут может получить указатель на объект из другого класса через соединитель, связывающий однотипные ссылочные атрибуты. Также, отношение можно реализовать непосредственно при создании объекта, если метод Create адресовать не целевому классу, а типизированному этим классом атрибуту отношения, причем атрибуту как прямой, так и обратной ссылки. Таким способом удобно создавать новый объект относительно другого объекта (например, новую Запись относительно Накладной). Также атрибут может получить IDO, создавая целевой объект отношения функционалом Autoset.

    Внешний пользователь не может просто так взять и присвоить атрибуту ссылочное значение. Печальные последствия открытия прямого доступа к системе внутренней идентификации очевидны и так, без комментариев. К тому же, за пределами пространства объектов отдельный дескриптор IDO что называется «теряет смысл», превращаясь в простое число.

    Поэтому, внешний пользователь может реализовать ссылку только опосредованно, в форме диалога, путем выбора элемента из списка, в котором каждый объект представлен своими абсолютными (не ссылочными) значениями. Требуемый список ему предоставляют компоненты слоя Data-курсоров (серверная часть интерфейсных ресурсов объектной СУБД будет рассмотрена впоследствии), которые затем и инициируют присвоение IDO в соответствии со сделанным выбором. Диалог выбора может быть прямым или каскадным, что задается на основе действующих back-соединителей. Источником для формирования диалогового списка выступает соответствующий список обратных ссылок.

    Функционал Autoset


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

    Функционал Autoset может быть инициирован как входящим соединителем, так и внешним событием Update. При этом целевой объект отношения будет создан функционалом только в том случае, если ссылочный атрибут в исходном объекте не имеет хранимого значения.

    Воспроизводство множества


    Существует твердое правило логического взаимодействия значений, согласно которому значение, принадлежащее определенному домену, можно связать только со значением, домен которого входит в исходный или включает в себя исходный. При этом принять исходное значение может только значение с равным или более обширным доменом. Самый большой домен (после Undefined Type) у атрибута типа Logical, который может принять значение любого другого типа. Проще говоря, соединителем можно связать только однотипные атрибуты, что и наблюдалось во всех рассматриваемых ранее примерах. Но вот в следующей декларации пассивный соединитель, связывая атрибуты обратной ссылки (A.{B} → C.{D}) очевидно разного типа, явным образом нарушает это правило, и тем не менее имеет полное право на жизнь.


    Все дело в том, что в данном случае предметом взаимодействия является не собственно значение, а количественный аспект связываемых множеств, принявших форму списков обратных ссылок. Рассмотрим подробнее логику происходящего.

    Статический атрибут, производное значение которого не инициализировано, при обращении к нему с запросом, тем не менее способен вернуть значение, сформировав его из входящих соединений, при их наличии. При этом, само хранимое значение атрибут все равно не создаст, так как запрос не содержит явного указания на принадлежность к транзакции, а значит база данных должна сохранить свое состояние неизменным. Иное дело, когда транзакционный характер воздействия очевиден. В этом случае не инициализированный ранее статический атрибут вполне может и должен в рамках общего изменения состояния базы образовать хранимое значение. Как видно из декларации, рассматриваемый соединитель и его целевой атрибут C.{D} будут инициированы при присвоении значения атрибуту C.[A], то есть транзакционно. И если производного значения в этот момент не существует, атрибут C.{D} начинает его формирование по исходному образцу, предоставленному соединителем.

    Как значение, список обратных ссылок производен от ссылок прямых. Иными словами, у атрибута C.{D} есть единственный способ сформировать собственный список размером с исходный, — это создать требуемое количество объектов класса D, и присвоить каждому из созданных объектов указатель на собственный объект. Такое создание с присвоением можно сделать одной командой Create в собственный адрес. Что атрибут (а если уж быть совсем точным – то функционал списка, назначенный атрибуту) и делает — для каждого элемента исходного списка. А так как значением этого элемента является ссылочный указатель, тип которого известен, то анализом кортежа класса создаваемого объекта определяется атрибут прямой ссылки требуемого типа, которому и присваивается извлеченное из элемента значение указателя.

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

    Внутренние отношения


    Для связывания однотипных объектов (объектов одного класса) используется отношение, создаваемое непосредственно внутри класса данных. При этом способ реализации собственно отношения остается неизменным – в классе создается два ссылочных атрибута, связанных ссылочными соединителями, и типизированных собственным классом.

    Что примечательно, рассмотренную в предыдущем параграфе корреспонденцию также можно отнести, пусть и частично, к внутренним отношениям, так как связывает она объекты, производные от одного класса. Правда делает это через объекты стороннего класса.

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

    Через внутреннее отношение атрибут может создать соединитель на самого себя. Это очень эффективный прием, позволяющий реализовать различного рода обобщения значений, включая обобщение «нарастающим итогом».

    Функциональный смысл внутреннего отношения определяется его типом.

    Цепочечное отношение


    Внутреннее отношение типа один-к-одному позволяет формировать из объектов класса последовательные цепочки, в силу чего и именуется цепочечным.

    Реализовать цепочечное отношение можно различными способами: как забирая соединителем указатель на предыдущий объект из списка обратных ссылок у общего владельца, так и используя функционал Autoset, который реализует отношение созданием последующего объекта относительно предыдущего. В последнем случае для инициации функционала удобно использовать метод-событие Update.

    Примеры использования – прохождение деталью цикла обработки, организованного как последовательность операций, или расчетные периоды года: квартальные или месячные, с нарастающими итогами на начало и конец периода. Если мощность цепочечного отношения увеличить до трех, объекты класса могут образовать логическое подобие трехмерной кристаллической решетки. Такую конструкцию можно использовать для самого различного моделирования поведения, и в том числе в физических средах.

    Рекурсивное отношение


    Внутреннее отношение типа многие-к-одному, именуемое рекурсивным, позволяет создавать образованные объектами древовидные структуры данных переменной глубины вложенности (объектные иерархии а-ля папки в файловой системе). Типичный пример использования рекурсии – календарный график работ на объекте строительства, в котором вместе с рекурсивным одновременно используется и цепочечное отношение. Самый удобный и естественный способ реализации рекурсивного отношения – создание объекта класса относительно уже существующего объекта-родителя.

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

    Правила взаимодействия с рекурсией


    Графически, правила взаимодействия сторонних классов с рекурсивным можно проиллюстрировать так:

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

    2. Только объект, принадлежащий самому верхнему уровню объектной иерархии (обладающий не инициализированным значением атрибута прямой ссылки рекурсии) может реализовать свою прямую ссылку на объект стороннего класса.

    Стоит отметить, что данные ограничения применимы только к реализации множественных отношений класса, обладающего внутренним рекурсивным отношением, с прочими классами, и не распространяются на аналогичные унитарные отношения. Эти правила, характерные для иерархий вообще, не являются строгими, а носят рекомендательный характер. Соблюдение этих правил на уровне объектной модели никак не контролируется, и целиком возлагается на интерфейсную частью приложения.

    Рекурсивная проекция


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


    Чтобы реализовать такую связь, класс-проекция также должен обладать декларацией рекурсивного отношения.

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


    Конструктор присваивает дополнительным атрибутам (на схеме отмечены символом [*]) тот же тип, что и атрибутам прямой ссылки проекции на связываемые классы, тем самым переводя их в разряд атрибутов отношения. Но есть отличие: обратной ссылки для дополнительных атрибутов не предусмотрено.

    Дополнительные атрибуты получают свое хранимое значение (указатель на объект) от однотипных им атрибутов прямой ссылки рекурсии, через активные соединители, на схеме отмеченные символом (=). Если оба значения получены, то будет реализована схема связи под номером 2. Если рекурсия в одном из связываемых проекцией объектов не реализована (схемы связи с номером 1 и 3), то соответствующий дополнительный атрибут не будет иметь хранимого значения, но при обращении к нему вернет указатель на объект без рекурсии. Такое поведение характерно для статических атрибутов, и уже упоминалось ранее: при обращении в методе Get к атрибуту, значение которого не инициализировано, он тем не менее способен сформировать возвращаемое значение путем опроса входящих соединителей. На схеме соответствующие пассивные соединители, созданные конструктором модели, изображены пунктиром.

    Стоит упомянуть, что совершенно аналогичный набор дополнительных атрибутов и соединителей конструктор модели создаст и в том случае, когда внутреннее рекурсивное отношение будет декларировано в таком варианте проекции как рассмотренная выше Корреспонденция.

    Структурный интерфейс


    Необходимость в структурном интерфейсе возникает всякий раз, когда требуется через отношения получить унифицированный доступ к разным сущностям. Иными словами, сущности с различным набором реквизитов надо свести в однородное (с точки зрения реквизитов) множество. Ну хотя бы затем, чтобы представить их общим списком.

    Первый вариант решения такой задачи нам предоставляет механизм наследования классов: класс-потомок наследует кортеж атрибутов класса предка. Этого вполне достаточно, например, чтобы все богатство видов финансовых документов свести в один список вида Дата, Номер, Наименование документа/Операция, Сумма.

    Такой вариант решения можно условно назвать интерфейсом "сверху". Работает он хорошо, но к сожалению не все сущности имеют общего предка. Типичный пример нам дает специфика учета в строительстве: несколько Заказчиков финансируют крупные Стройки, которые состоят из нескольких Объектов строительства, Работы по которым структурированы по Видам работ, и включены в различные ДоговорыЗаказчиком). Требуется ход выполнения работ (финансирования, произведенных расходов, человеко-часов,...) свести в общую картину а-ля диаграмма Гантта. Множественное наследование не является хорошей идеей. К тому же, эффект множественного наследования можно получить, объединяя разнотипные сущности связью один-к-одному, – в чем, по-видимому, и состоит философский смысл унитарного отношения. Для нашего примера результат достигается комбинированием унитарного отношения и рекурсии, и в декларациях выглядит например так:

    Каждый из перечисленных выше субъектов «строительного» учета автоматически (используя Autoset) создает парный себе объект в классе Гантт, после чего передает в этот объект указатель на своего логического "владельца" (в качестве значения атрибута прямой ссылки рекурсии), а также прочие свои значения. Передача указателя на “владельца" осуществляется через вспомогательные атрибуты, такие же как и на схеме рекурсивной проекции, на которой они обозначены символом [*]. И создание объектов Гантт, и передача значений их атрибутам, осуществляется через унитарное отношение, логически связывающее «две части одного целого».

    Такой вариант решения можно (также условно) назвать интерфейсом "сбоку" (специалисты по терминологии нас поправят), поскольку существует еще один способ единообразного представления сущностей, которому очень подходит название — интерфейс "снизу". Его идея заключается в том, чтобы в качестве значения хранить в атрибуте унифицированную структуру данных на правах значения интерфейсного типа, в которую и передавать значения, требующие унифицированного представления. Так в частности «работают» бухгалтерские "проводки", которые совершенно одинаково выглядят относительно регистра учета, несмотря на то, что размещены в разных классах-документах, и зачастую не в единственном экземпляре.

    Наверное стоит отметить, что существование столь разных вариантов частичной структурной унификации наталкивает на мысль о том, что универсального интерфейсного решения в природе не существует.

    Интерфейсный тип


    В объектной модели данных любой структурный тип самым естественным образом существует на правах пользовательского класса, идентификатор которого (IDC) и является дескриптором этого типа данных. Соответственно, интерфейсную структуру данных можно определить как класс, а ее использование в качестве значения атрибута следует рассматривать как своеобразную модификацию унитарного отношения, при которой атрибут прямой ссылки на интерфейсный класс хранит не идентификатор объекта интерфейсного класса (IDO), а собственно сам объект. Так как «включаемый» в качестве значения объект теряет свою самостоятельность, то вместе с ней он перестает обладать и собственным дескриптором. Теперь его идентификатором является составное значение в терминах IDO объекта-владельца +IDA атрибута, в котором он размещен. Такое решение позволяет не беспокоиться о способе создания включенного объекта и реализации отношения с ним – все это происходит автоматически при создании объекта-владельца в ходе инициализации его атрибутов.

    Так как изначально предполагается, что «интерфейсный» объект будет включен в состав объектов самых разных классов, то традиционный способ обеспечения симметрии отношения путем создания ссылочного атрибута в каждом из связываемых классов перестает быть оптимальным. В самом деле, при таком способе в кортеже «интерфейсного» класса будет декларировано энное количество ссылочных атрибутов, из которых при собственно реализации отношения получит значение всегда только один. Поэтому был выбран другой вариант, асимметричный в декларации, но тем не менее сохраняющий ссылочную симметрию при реализации.

    В интерфейсном классе роль атрибута обратной ссылки для всех создаваемых интерфейсных отношений выполняет один и тот же атрибут – Own, которому, чтобы он мог принять значение любого ссылочного типа, принудительно назначен тип User Defined Type. Собственно говоря, назначение этого типа атрибуту Own и играет роль флага, отмечающего класс как "интерфейсный".
    Итоговые декларации "интерфейсного" отношения (справа), в сравнении с декларациями обычного унитарного отношения (слева), выглядят так:

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

    Служебные классы


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

    Супер-класс


    Множество объектов данных, симметрично связанных взаимными ссылками, представляет собой замкнутую систему, в пределах которой естественная меж-объектная навигация не ограничена ничем. Но так как по соображениям надежности и безопасности прямой доступ к объектам запрещен, возникает проблема входа в такую систему. Преодолеть ее помогает использование служебного класса, именуемого Супер-класс, и производного от него Супер-объекта, с фиксированными значениями дескрипторов IDC и IDO.

    При создании дизайнером приложения каждого нового пользовательского класса, для этого класса автоматически создается множественное отношение с Супер-классом. Тем самым, упомянутый ранее набор служебных атрибутов класса (Type, Own и Del) дополняется четвертым членом – атрибутом прямой ссылки на Супер-класс. Супер-класс же, в свою очередь, получает атрибут обратной ссылки, типизированный дескриптором IDC вновь созданного класса. Таким образом, по факту создания пользовательских классов, Супер-класс становится своего рода владельцем их полного множества, что позволяет использовать Супер-класс с его фиксированным дескриптором как точку входа в действующую модель данных. Что примечательно, атрибутный идентификатор (IDA) обратной ссылки в Супер-классе странным образом совпадает по значению с ее классовым идентификатором (IDC).

    В процессе создания классом производного объекта (Create) выполняется автоматическая инициализация его служебных атрибутов, и в том числе атрибута прямой ссылки на Супер-класс, который получает фиксированный IDO Супер-объекта. При этом, как следствие, указатель на новый объект пополняет собой соответствующий список обратных ссылок Супер-объекта. Таким образом, исключительно по факту соблюдения стандартных правил реализации отношений, Супер-объект становится владельцем списков объектов каждого класса, иными словами – полного множества объектов. Это обстоятельство позволяет использовать Супер-объект как естественную точку входа в базу данных, открывающую доступ к спискам объектов классов.

    Обратим внимание на важный момент – класс данных, как декларация, не обладает физическим указателем на список собственных объектов. Между данными и метаданными не может быть иной связи, кроме логической.

    И еще одна деталь: при организации диалога выбора объекта, Data-курсор по умолчанию, если не задано иное, использует список обратных ссылок целевого класса из Супер-объекта.

    Класс Global


    Любое приложение нуждается в глобальных значениях, перманентно доступных всем частям приложения. Для декларации таких значений используется служебный класс Global, в производном объекте которого они и хранятся. Спецификой класса Global является тот факт, что он связан с Супер-классом не множественным отношением, как все прочие классы, а унитарным отношением один-к-одному. Иными словами, относительно Супер-объекта объект Global существует в единственном экземпляре, а так как его позиция в кортеже Супер-объекта известна, то доступ к его значениям осуществляется в один шаг.

    В зависимости от особенностей их использования, все множество глобальных значений можно условно разделить на группы. В первую группу входят изолированные значения, которые используются сами по себе, как правило в интерфейсных формах, как например, Наименование организации (собственной). Для доступа к таким значениям достаточно маршрута: Супер-классGlobalАтрибут.

    Вторую группу образуют так называемые заимствуемые значения, такие как Ставка НДС. Для того, чтобы воспользоваться заимствуемым значением, класс должен обладать отношением с классом Global, и очевидно – множественным. Если такое отношение декларируется, то конструктор модели в дополнение к нему создает соединитель, позволяющий создаваемому объекту автоматически получать указатель на объект Global.

    Помимо абсолютных, глобальными могут быть также и ссылочные значения. Такие значения чаще всего используют в качестве значений по умолчанию, задаваемых при настройке приложения, например, ссылки на объекты Валюты, образующие пару Рубль-Доллар. Так как отношение типа многие (Global) -к- одному (Валюта) будет напрягать здравый смысл, глобальные ссылочные значения создают несколько иначе: сначала создается Undefined Type атрибут, в атомарной (для единственной ссылки) или перечислимой (для нескольких ссылок) форме, а затем его тип переопределяется на User Defined Type = IDC целевого класса. Иными словами, атрибут прямой ссылки создается без декларации собственно отношения. Этот прием используется везде, где нет практического смысла декларировать отношение, а атрибут нужного типа необходим (как, например, при реализации рассмотренной выше рекурсивной проекции).

    Кроме этого, все значения, хранимые объектом Global, подразделяются на общие и пользовательские. Общие, такие как Наименование организации или Ставка НДС, одинаковы для всех пользователей базы данных. В отличие от Отчетного периода или указателя на Склад по умолчанию (для конкретного кладовщика, например), которые должны быть индивидуальны для каждого пользователя. Для образования и хранения пользовательских значений используются объекты класса User.

    Класс User


    Основное назначение класса User состоит в том, что на его основе строится система аутентификации конечных пользователей базы данных. Если в ходе авторизации введенные пользователем логин и пароль совпадают со значениями соответствующих атрибутов в одном из объектов User, то авторизация считается успешной, после чего значения всех прочих атрибутов данного объекта становятся доступны этому пользователю (и только ему) на правах глобальных значений.

    Реализуется это следующим образом. Классы Global и User связаны множественным отношением. При создании нового статического атрибута в классе User, в классе Global автоматически создается парный ему однотипный и одноименный динамический атрибут (пользовательский), который после создания получает пассивный входящий соединитель от парного ему атрибута в User. При обращении к пользовательскому атрибуту в Global, этот атрибут делает попытку получить свое значение через соединитель, и в этот момент среда исполнения вместо списка обратных ссылок на объекты User подставляет указатель на единственный такой объект, полученный при авторизации пользователя.

    Отметим, что атрибут может получить свое значение по соединителю через список обратных ссылок из множества источников или преобразованием этих значений в единственное (например, суммированием), или при наличии условия (контекста), позволяющего выделить из множества значений единственное. В отсутствие соответствующего условия или преобразования (функционала), атрибуту запрещено создание входящего соединителя через атрибут обратной ссылки. Для пользовательского атрибута в классе Global это ограничение преодолевается искусственным путем.

    Локальные базы данных


    Несколько выше по тексту уже упоминалось, что множество связанных отношениями объектов образует замкнутую систему, единственной точкой входа в которую является Супер-объект. В пределах одной физической базы данных может существовать произвольное множество таких замкнутых систем. Каждую такую систему можно рассматривать как логическую базу данных, полностью изолированную от других таких же логических баз. У каждой логической базы есть своя точка входа, свой Супер-объект. Иными словами, для генерации новой логической базы необходимо создать еще один объект, производный от Супер-класса.

    Решается эта задача при помощи трех служебных классов: UserGlobal: Супер-класс, причем ведущим в этой связке будет класс Global. Именно класс Global ассоциируется с логической базой данных, а каждый производный объект этого класса в соответствующем атрибуте хранит в том числе пользовательское наименование «своей» базы. Наличие отношения один-к-одному позволяет при создании объекта Global автоматически создавать и связывать с ним новый Супер-объект. Относительно объекта Global (рассматриваемого как экземпляр логической локальной базы) создаются объекты класса User (именованные Пользователи этого экземпляра локальной базы). После прохождения процедуры авторизации, для данного Пользователя в его записи в Таблице Клиентов хранятся дескрипторы (IDO) не только объекта Users, но и связанных с ним объектов Global и Супер-. Именно пользовательский указатель на Супер-объект (корневой элемент локальной базы данных) и будет использован системой управления в качестве значения, которое автоматически присваивается соответствующему служебному атрибуту объекта любого класса, при создании этого объекта по инициативе данного конкретного пользователя.

    Что важно отметить — все взаимно-изолированные логические базы данных подчиняются общим для них правилам модели данных, которые действуют на всем пространстве физической базы данных.

    Наследование отношений


    При своем создании класс-наследник получает полный кортеж атрибутов класса-предка, и вместе с атрибутами отношения класс-наследник получает в полном объеме комплект отношений класса-предка. И при этом всплывает интересная деталь.

    Каждый новый класс, независимо от способа его создания, должен образовать собственное отношение с Супер-классом, чтобы иметь полный список своих объектов в явной форме. Но класс-наследник не может напрямую создать такое отношение, так как уже наследует атрибут прямой ссылки на супер-класс в составе всего кортежа предка. Кроме того, хотя класс-предок и не создает собственных объектов, тем не менее его список обратных ссылок в супер-объекте должен включать в себя полный список объектов, производных от всех его дочерних классов. (Для примера: есть множество всех Документов вообще, и есть частное множество только Накладных.)
    Список объектов для класса-предка будет формироваться и безо всякого вмешательства в существующие декларации, так как все его наследники получили его родительское отношение с супер-классом. Применительно же к классу-наследнику конструктор классов реализует частичное создание нового отношения – используется существующий атрибут прямой ссылки (новый не создается), ему в пару создается атрибут обратной ссылки в супер-классе, и оба атрибута связываются ссылочным соединителем.

    Таким образом, при наследовании частично нарушается двусторонняя симметрия отношения с супер-классом: одному прямому указателю на супер-объект теперь будет соответствовать два и более (зависит от глубины наследования) указателя обратной ссылки в супер-объекте. Но такое исключение из правил носит частный характер и представляется логически оправданным.

    Уточнение домена


    Домен значений ссылочного атрибута образован идентификаторами объектов, производных от оппозитного класса отношения и всех его классов-наследников. В прикладных задачах зачастую возникает потребность принудительно сузить домен значений ссылочного атрибута, ограничив его единственным классом.

    Рассмотрим следующий пример:

    Абстрактный Контрагент имеет одну из двух организационных форм: Юридическое или Физическое лицо (наследники класса Контрагент). В товарообменных сделках Контрагент играет определенную Роль: он может быть Поставщиком, Покупателем или и тем и другим одновременно. Очевидно, что между Контрагентом и Ролью существует вполне конкретное отношение, которое отдельно рассмотрим чуть позже. Класс Накладная представляет собой абстрактную товарообменную операцию, в которой декларированы естественные множественные отношения с Контрагентом и Ролью. В нашем же примере конкретных операций ровно две: Приходная и Расходная, наследники Накладной и ее отношений.

    Наследники Накладной используют отношение с Контрагентом в том виде, в котором его унаследовали. И Приходная и Расходная накладные реализуют это отношение, выбирая целевой объект из общего списка Контрагентов, в котором в равной степени присутствуют и Юридические и Физические лица.

    Унаследованное же отношение с Ролью требует переопределения, так как предметом ссылки для Приходной накладной может быть только Поставщик, а для Расходной — только Покупатель. Переопределение унаследованных отношений (сужение домена) достигается путем замены в свойствах атрибута идентификатора класса-предка на идентификатор класса-наследника, для чего ссылочный атрибут предоставляет конструктору модели соответствующий диалог. Обратим внимание, что после уточнения отношения со стороны прямой ссылки в Приходной и Расходной накладных, в списки обратных ссылок Поставщика и Покупателя автоматически попадут только объекты накладных, соответствующие их роли. Но симметричное переопределение отношения также и для ссылочных атрибутов этих классов будет считаться хорошим тоном.

    В предыдущем примере Накладная логически связывает Контрагента с его Ролью. Рассмотрим эту связь чуть подробнее, используя тот же набор классов, но представленный в несколько ином ракурсе:


    Контрагент может одновременно быть и Поставщиком и Покупателем. Этот факт декларируется созданием двух раздельных унитарных отношений Контрагента с этими классами, без создания общего отношения с Ролью. Вместе с тем общий предок Роль необходим, так как несет в себе не только отношение с Накладной, но и общий для Поставщика и Покупателя дополнительный комплект атрибутов, необходимый, например, для организации различных взаиморасчетов. Логическая же связь Контрагента с Ролью выглядит следующим образом (на примере пары ПоставщикПриходная накладная): Контрагент приобретает статус Поставщика (образует объект класса Поставщик, и реализует отношение с этим объектом) при наличии хотя бы одной Приходной накладной. Для того, чтобы эта связь получила физическую реализацию, и работала как внутреннее правило модели данных, следует использовать функционал Autoset, как показано на рисунке:


    Из левой части рисунка видно, что наличие унитарного отношения между Контрагентом и Поставщиком позволяет Приходной накладной потенциально получить значение для любого из своих атрибутов прямой ссылки при присвоении указателя другому атрибуту прямой ссылки. Но так как логически Поставщик у нас вторичен, то функционал Autoset назначается атрибуту прямой ссылки на Поставщика. При этом назначении автоматически будет создан дополнительно двунаправленный соединитель типа back-. При наличии этих деклараций, в процессе исполнения, после выбора в накладной объекта Контрагент, произойдет одно из двух. Если у Контрагента указатель на Поставщика актуален, то соединитель передаст его соответствующему атрибуту Накладной. А иначе back-соединитель инициализирует функционал Autoset, обязывающий владеющий им ссылочный атрибут безусловно реализовать отношение, в данном случае – путем создания объекта целевого класса. После того, как объект Поставщик будет создан, и указатель на него будет присвоен атрибуту прямой ссылки, тот же самый back-соединитель реверсом передаст этот указатель в объект Контрагент.

    Еще один пример на тему уточнения отношения представлен на следующем рисунке:


    Объекты типа Запись всегда создаются в контексте объекта Накладная событием Create, адресованным его атрибуту обратной ссылки на Запись. Соответственно для того, чтобы создавался объект нужного класса, строго необходимо уточнение целевого класса обратной ссылки. Переопределение класса в свойствах атрибута прямой ссылки в дочерних классах Запись рекомендовано, но не является обязательным.

    Селективная передача значения


    Значение атрибута S из класса B раздается тремя соединителями: одним общим – в атрибут S класса-предка A, и двумя частными – в атрибуты Д и К его наследников А1 и А2. В зависимости от того, указатель на объект какого из наследников, А1 или А2, будет получен объектом В, в адресуемом объекте только один из двух атрибутов, Д или К, получит свое значение. Атрибут S получит свое значение в любом случае.


    Такое поведение обеспечивается селективными свойствами ref-контекста соединителя, а именно – благодаря наличию в декларациях ref-сокета идентификатора IDC целевого класса соединителя. Внешний соединитель исполнит свою передаточную функцию только в том случае, если ref-контекст предоставит ему IDO целевого объекта. А это произойдет только в том случае, когда значение ссылочного атрибута – IDO объекта входит в домен значений типа, декларированного в свойствах ref-сокета.

    Ну просто напрашивается ассоциация с оператором if, который перед выполнением действия проверяет соответствие типов.

    Резюме


    Симметричная форма реализации связи объектов, основанная на взаимном обмене идентификаторами, способна автоматически поддерживать ссылочную целостность и логическую согласованность средствами управления самой базы данных. Помимо этого, симметрия связи делает возможной естественную (no Select) навигацию в многомерном пространстве объектов данных.

    Собственно говоря, способы интеграции бизнес-логики приложения непосредственно в логическую структуру базы данных, рассмотренные в этой, а также в предыдущей публикации, позволяют в разы увеличить скорость создания приложений. Согласитесь, визуальное конструирование существенно проще, чем написание и отладка программных кодов.
    Поделиться публикацией
    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое