! | Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам) |
Приложениям и всем множественным уровням инкапсуляции запросов и итераторов бывает необходимо сохранить какой то свой локальный приватный контекст, связанный с итератором.
Чаще всего речь идет о необходимости создания некоего кеша перед первой итерацией запроса и использование его на последующих шагах.
Такой контекст можно добавлять под своим приватным ключем (key) в CQueryIfaceGp::x_rQmap проперти итератора. Метод CQmapIfaceGp::MapObject() одновременно позволяет присоединить по ключу прикладной объект любого локального типа к итератору и получить его потом на следующих итерациях. Возвращаемое значение можно использовать для выбора момента инициализации:
CMyStorage::Iterate/Query() { ref<CMyContextData> rMyContextData; if (out_i.GetCurrentQuery()-> x_rQmap-> MapObject( _m_keyMyPrivateContext, QMAP_OBJECT(rMyContextData))) { // init rMyContextData before first iteration rMyContextData->BuildCaches(); }
Макрос QMAP_OBJECT() должен использоваться вместо вторых двух параметров метода для передачи контекстного объекта с безопасным контролем его типа.
Разные уровни инкапсуляции итератора могут добавлять свои контексты к нему, каждый под своим уникальным ключем. Ключ рекомендуется генерировать случайный и хранить в соответствующем инкапсуляторе:
class CMyStorage { public ... Iterate/Query(...); private: key _m_keyMyPrivateContext = key::GNewUniqueKey();
Уникальную константу key::GConstKeyStr() потенциально можно было бы использовать вместо этого но она создает как проблемы придумывания уникальных строчек так и локализации контекста в разных экземплярах вложенных инкапсуляторах одного типа. Поэтому рекомендуется именно хранить случайный уникальный ключ в каждом объекте инкапсулятора.
Имеется например хранилище, с итератором, получающим список критериев который требует нетривиальной конвертации в список другого формата для передачи в хранилище более низкого уровня. Список полей Bics в Costo:
bool CCostoRelaStoreImpl::OnIterateBicsObjectValuesForObject( .... ref<CBicsObjectFieldListIfaceGp> rBicsObjectFieldList, out iter& out_i, ...)
Конверсия делается перед первой итерацией, результат сохраняется "в итераторе" и используется до конца цикла:
bool CCostoRelaStoreImpl::OnIterateBicsObjectValuesForObject( ... { // convert Bics field list to Rego field map on initial iteration ref<CRegoFieldMapIfaceGp> rRegoFieldMap; if (out_i.GetCurrentQuery()-> x_rQmap-> MapObject( _m_keyQmapRegoFieldMap, QMAP_OBJECT(rRegoFieldMap))) { rASSERT(out_i.IsBeforeFirstIteration()); // Conversion ref<CBicsObjectFieldIfaceGp> rIterBicsObjectField; for ( iter i; rBicsObjectFieldList-> Iterate( out i, out rIterBicsObjectField);) { rRegoFieldMap-> AddFieldKey( rIterBicsObjectField-> GetBicsUniqueKey()); } } else { rASSERT(!out_i.IsBeforeFirstIteration()); } // Call lower level ref<CRegoObjectFieldIfaceGp> rRegoObjectField; rp<CRegoValueIfaceGp> rpRegoValue; if (x_rRegoStore-> IterateBicsObjectValuesForObject( rRegoFieldMap, // converted list
На практике сконвертированные списки критериев в целях оптимизации запросов может понадобится хранить "глобально" а не только в рамках одного цикла. Но в контексте итератора все равно нужно однократно определить и выбрать ссылку на параметры запроса в эффективном формате.
В CQmapIfaceGp прослеживаются явные аналогии с unidef. Это маппинг данных неопределенного типа по ключам. В отличии от unidef объекты не образуют иерархию, не являются скалярами а ref<object>, и ключи не явные иерархические строковые пути а одноуровневый key.
Применение Qmap за пределами вышеописанного сценария сейчас запрещено.