! | Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам) |
M2M связь многие-к-многим традиционно декларируемая реляционно
CDbMappingTable { x_keyObject1 x_keyObject2 x_keyLinkType x_other_link_attributes }
имеет недостатки
Декларация таких связей этим хаком не выразимым реляционно напрямую приводит к неэффективности, отсутствию статического контроля в "лучшем" случае подмененного рантайм отказами и/или к копи пасте логики и деклараций.
Поэтому связи, где композитным первичным ключем по сути являются внешние ключи двухдругих объектов БД уникально связанных заданным типом связи в Udb поддерживаются напрямую. В том числе и чтобы более эффективно воспользоваться средствами Bijouфундаментально транслирующих все данные в связи такого вида.
Связь декларируется CDb-классом наследованым от mmdbobject
class CDbPrjXxxmapping : public mmdbobject { ... };
Он может быть и пустой. Основные параметры связи наследуются от mmdbobject исключая их некорректную инициализацию. Только дополнительные свойства связи декларируются в этом классе как обычные проперти. Таким образом M2M связь имеет встроенную поддержку + гибкие возможности расширения обычными средствами Udb.
Такие CDb классы можно размещать только в специальных маппинговых контейнерах dbmm<>. Они похожи на dblist но вместо добавления произвольных элементов доступ к MM связям осуществляется функцией
ref<TYPE> dbmm::MapContainerToTrait( key keyMmTrait, key keyMmTie, ENetworkSync eNetworkSync = E_NetworkSync_Yes)
При вызове ее в форме
ref<CDbMyMapping> rDbMapping = _x_rDbContainer-> _x_dbmmMyMapping.Get(). MapContainerToTrait( keyTrait, keyTie);
задаются все три необходимых и фиксированных ключа идентифицирующих связь:
От mmdbobject наследуются следующие встроенные атрибуты M2M связи:
Обязательно применять при изменении 4) x_sMmScalar/x_keyMmNonscalar и дополнительных свойств связи как это делается с любым CDb объектом.
Как любых других записей.
Декларация MM CDb класса позволяет использовать его в Qx запросах точно так же как и любой другой класс. Свойства пропертей можно JOINить с другими таблицами и использовать с фильтрами.
В выражениях Qx можно непосредственно записывать вызовы функций GetMmTraitKey() и GetMmTieKey() и они (точно так же как вызовы GetKey/GetDbContainerKey для обычного dbobject) транслируются в корректный SQL.
Таким образом M2M связи представленные через dbmm ничего не теряют в совместимости с обычной реляционностью и не требуют никаких специальных хаков (к Bijou) мимо Udb.
Это единственная фича работающая для сабжа особым образом если применяется с Bijou и не имеющая эффекта для простого реляционного бакенда (как драйвера SQLite).
Если MapContainerToTrait() использующей системный TieProp в качестве keyTrait указан ключ, совпадающий со статически декларированным проперти CDb объекта контейнера то значения Scalar/Nonscalar будут указывать на одно и то же значение со статическим проперти.
Это дает возможность работать с именованными пропертями объектов как с обезличенными списками включающими и динамические проперти (добавляемые пользователем).
Естественно использование такого мапинга требует обязательной статической проверки связанности всех имен с ключами (GET_PROPERTY_NAME / ASSERT TBD). Рефакторинг статических деклараций никогда не должен приводить к неожиданным деградациям логики фактически использующей метаданные. Поэтому частью статических деклараций должно быть явное указание на их участие в динамических связях (TBD).
При этом если не добавлять в мапинг Trait совпадающий со статическими пропертями он сам там не появится. Это исключает какие бы то ни было случайные завязки логики на статические декларации.
Нет.
Как нет отдельно различимого NULL значения у str, int и т.п. пропертей на которые связи могут маппироваться. Приложения могут объявлять свои x_bXxxValueAssigned флаги как параметры связи чтобы отличать неопределенные значения от пустых.
Тип первого/основного объекта ограничен классом контейнера в котором dbmm объявлен. Ограничения на keyTrait и keyTie - TBD
Нельзя декларировать несколько dbmm маппирующих даже в разных контейнерных классах множественные связи одного и того же типа для одного и того же первичного ключа. С точки зрения Bijou все записи во всех таблицах с одним первичным ключом образуют единый объект и декларации нескольких маппингов будут конфликтовать с неопределенным результатом (после выполнения CommitRef) если хранят связи одного типа.
Object --property--> Id = Scalar
как keyPatient->"Sex" = "Female"
Object --attach--> Attachment
как keyLetter --C_keyTieAttachFile--> keyFile
keyTopic1 --add parent--> keyTopic2
Пропертей не имеет.
keySceenshot --class--> keyImageClass
keyBug123 --category--> keyBugs
Часто попытки добавить дополнительные атрибуты сюда являются аномалиями чтобы избежать регистрации других независимых связей и могут нарушить нормализацию. Как например Bijou для компактности журнала считает keyContainer атрибутом Node --class--> ... ограничивая Node одним возможным контейнером.
Bug --synonym--> Defect
Array --see also--> List
Особенность в том что оба объекта симметричны. Создание двух копий связи в обоих направлениях было бы ошибкой.
keyTask --in version--> Release_1.3.7 = "Beta" keyDevice --assembly--> keyAssemblyOperation = "Complete"
Может иметь проперти определяющие более сложные значения, ссылки, диапазоны. Может быть по сути частью более сложных тройственных связей. Значением связи может быть ключ объекта более полно описывающего связь если на него нужны ссылки и из других мест (обычная нормализация данных).
keyNonscalar автоматически маппируется Bijou на значения ключей в пропертях чтобы отличать их от строк. Все остальное - sScalar. Оба значения сразу заданы быть не могут.
Основное встроенное значение скаляра используется для эффективной и универсальной обработки в Bijou для основных, как правило читабельных пользователем, скалярных значений как
В дополнительных свойствах связи могут содержаться
В свойствах связи не могут содержаться данные по сути составляющие независимый объект БД требующий на себя внешние ссылки и цикл жизни которых может не совпадать с существованием связи, а так же дублирующиеся данные и не имеющие прямого отношения к связи а описывающие один из объектов в ней участвующих.
Классика:
Аuthor --written--> Book
легко представима в CDbAuthor::_x_dbmmBooksWritten так как подразумевает что данный автор имеет только единственную связь типа "написал" c книгой.
Сложнее ситуация если мы захотим хранить
Аuthor --edited--> Book
и таких правок одной и той же книги может быть много. Напрямую такая связь не предствима в dbmm и нам требуется введение дополнительного объекта CDbEdition:
Аuthor --edited--> Edition + CDbEdition::x_keyBook
Книги же которые написал автор нужно получать динамически запросами к Edition этого автора.
Запрещено паразитировать на keyTie для обозначения третьего объекта! Он может быть только из набора декларированных типов связи. Тройственные и более уникальные и не уникальные связи и атрибуты этих связей требуют деклараций дополнительных CDb объектов по аналогии с "Аuthor --edited--> Edition" выше.
С точки зрения реляционной декларации казалось бы все равно
Аuthor --writes--> Book OR Book --written by--> Аuthor
Логика может работать и так и так. Для выбора первого/главного объекта нужно учитывать
В случае
keyPatient->"Sex" = "Female"
ясно что значения живут вместе с пациентом и связи должны удаляться с ним. И
keySexField --property of--> keyPatient = "Female"
практически абсурден. Даже если мы удалили поле карточки из конфига мы можем оставить уже заданные его значения для существующих пациентов. Первый вариант записи обеспечивает это.
В
keyChildTask --add parent--> keyParentTask
или
keyParentTask --parent of--> keyChildTask
вопрос ставится так: хотим ли мы чтобы при удалении дочерней задачи ссылки на нее продолжали висеть в родительских и при удалении родительских что должно оставаться в дочерних. Возможно мы и не захотим применять каскадное удаление и саязь будет жить сама по себе или удаляться с любым из двух объектов.
Связь
keyLetter --attach--> keyFile
видимо верна в таком виде если письмо это контейнер и даже при удалении файла мы можем хотеть чтобы в письме осталась ссылка на то что файл там был. Для файла же исчезновение всех связей может означать что он мусор и подлежит уничтожению сам.
То есть выбор контейнера и Trait, теоретически симметричных, зависит от прикладной логики. Иногда - как для таблиц синонимов и "see also" первичного объекта в принципе нет.
Эта категория в данный момент пуста.