Описание реализации временных объектов на временных таблицах

Материал из RSB-Doc
Перейти к: навигация, поиск

Содержание

Общие положения

Все такие объекты являются потомками либо статического объекта «Родитель временных объектов», либо «Родитель временных древовидных объектов». Временные объекты удаляются либо при перезагрузке сервера приложений, либо при помощи унаследованного метода «Родитель временных объектов».DeleteTmpChildTI. Все данные временного объекта находятся в локальной временной таблице MS SQL Server’а, имя которой начинается с символа «#». Для системы отчетности зарезервированы префиксы имен таблиц «#rpt». Время жизни временной таблицы отличается от времени жизни соответственного временного объекта. Временная таблица содержит для каждого клиента независимые данные и при закрытии клиента вызывается уничтожение временной таблицы с данными этого клиента (см. реализацию временных таблиц в MS SQL Server). Временный объект поддерживает большинство стандартных методов объектов. Если необходимо использовать методы древовидного объекта, то необходимо создавать временный объект вызовом метода «Родитель временных древовидных объектов».AddTmpChildObj.

Создание временного объекта на временной таблице

Метод «Родитель временных объектов».AddTmpChildObj.

В качестве параметров передаются:

  1. Имя создаваемого объекта [in, required],
  2. Имя временной таблицы [in, required],
  3. XML — описание полей создаваемого объекта [in, required],
  4. GUID создаваемого объекта [in, optional]. Если отсутствует, то генерится автоматически.

Если данный объект уже существует, то происходит удаление существующих данных из временной таблицы.

Пример(RSL):

  var sXML;
  sXML = "<Comment>Выходной объект для Оборотной ведомости по дате</Comment>"
    + "<Field Name='Идентификатор' Type='FT_Int32' Flags='0x1b'   DBCode='ID'/>"
    + "<Field Name='Дата'          Type='FT_Date'  Flags='0x8009' DBCode='DateReg'/>"
    + "<Field Name='Нач. остаток'  Type='FT_Money' Flags='0x5'  DBCode='BegRemains'>"
    + "<DefaultValue>0.0000</DefaultValue>"
    + "</Field>"
    + "<Field Name='Приход'        Type='FT_Money' Flags='0x5'  DBCode='InCome'/>"
    + "<Field Name='Расход'        Type='FT_Money' Flags='0x5'  DBCode='OutCome'/>"
    + "<Field Name='Кон. остаток'  Type='FT_Money' Flags='0x5'  DBCode='EndRemains'/>"
    + "<Field Name='Дельта'        Type='FT_Money' Flags='0x5'  DBCode='SumDelta'/>";
 
  var dsRootTmp = GetDS("Родитель временных объектов", null, 1);
  dsRootTmp.RSObject.Run("AddTmpChildObj",
                         "Объект Оборотная ведомость по дате",
                         "#rptRevSheetDate",
                         sXML,
                         "78D85683-75C5-41BF-8E7F-6C007241BB05");

Заполнение временного объекта данными.

Для получения всех преимуществ исполнения SQL-запросов реализован парсер, который обрабатывает запрос написанный на языке, использующем синтаксис SQL.

Пример:

На вход парсера подается следующий запрос:

 -- Отчет: Оборотная ведомость по дате. 
 INSERT INTO "Объект Оборотная ведомость по дате"("Дата", "Приход", "Расход", "Дельта")
 SELECT DateReg, SUM(InCome), SUM(OutCome), SUM(InCome) - SUM(OutCome)
 FROM (
       SELECT 0 AS DateReg,
              0 AS InCome,
              0 AS OutCome
       FROM "Товарный документ" synWareDoc
       UNION ALL
 ...
       UNION ALL
       SELECT synWareDoc."Дата регистрации" AS DateReg ,
              0 AS Income ,
              SUM(synWareDoc."Сумма в базовой валюте") AS OutCome
       FROM "Товарный документ" synWareDoc
       WHERE (synWareDoc."Дата регистрации" >= {ts '2005-01-12 00:00:00'}) AND
             (synWareDoc."Дата регистрации" <= {ts '2005-12-12 00:00:00'}) AND
             (synWareDoc."Откуда организация" IN (5006, 5012, 5014)) AND
             (synWareDoc."Откуда подразделение" IS NULL) AND
             (synWareDoc."Откуда склад" IS NULL) AND
             (synWareDoc."Откуда МОЛ" IS NULL)
       GROUP BY synWareDoc."Дата регистрации"
      ) mytbl
 GROUP BY DateReg

В SQL Server передается следующий результат парсинга:

 -- Отчет: Оборотная ведомость по дате. 
 INSERT INTO #rptRevSheetDate ( DateReg , InCome , OutCome , SumDelta )
 SELECT DateReg , SUM ( InCome ) , SUM ( OutCome ) , SUM ( InCome ) - SUM ( OutCome )
 FROM (
       SELECT 0 AS DateReg ,
              0 AS InCome ,
              0 AS OutCome
       FROM (SELECT cowWareDoc.* FROM cowWareDoc) synWareDoc
       UNION ALL
 ...
       UNION ALL
       SELECT synWareDoc.DateReg AS DateReg ,
              0 AS Income ,
              SUM ( synWareDoc.SumBase ) AS OutCome
       FROM (SELECT cowWareDoc.* FROM cowWareDoc) synWareDoc
       WHERE ( synWareDoc.DateReg >= { ts '2005-01-12 00:00:00' } ) AND
             ( synWareDoc.DateReg <= { ts '2005-12-12 00:00:00' } ) AND
             ( synWareDoc.SourcOrg IN (5006, 5012, 5014) )          AND
             ( synWareDoc.SourcOffice IS NULL )                     AND
             ( synWareDoc.SourcWareh IS NULL )                      AND
             ( synWareDoc.SourcOwner IS NULL )
       GROUP BY synWareDoc.DateReg
      ) mytbl
 GROUP BY DateReg

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

Основные правила и ограничения запросов.

  1. Выполняются только запросы на изменение, добавление или удаление данных во временных объектах на временных таблицах(INSERT, UPDATE, DELETE).
  2. Парсер осуществляет ограниченный разбор синтаксиса запроса. В связи с этим возможна ситуация, когда парсер успешно разобрал запрос, но его забраковал SQL Server.
  3. В запросе можно использовать только синтаксис SQL92 с заменой имен таблиц и полей СУБД на имена TypeInfo.
  4. Допускаются только строковые имена объектов и их полей из TypeInfo. Все явные имена из базы запрещены. Например, допустимо «Сводная расшифровка спецификации», «Товарный документ», «Система скидок» и т. п.; запрещено — cowDocDet, cowWareDoc, SystemDisc и т. п.
  5. Запросы могут включать в себя подчиненные и составные запросы.
  6. Запрещено использование «*» для извлечения всех полей в предложении SELECT. Необходимо всегда явно указывать выбираемые поля.
  7. В предложении FROM необходимо для всех элементов использовать алиасы.
  8. Для полей результата в подчиненных и составных запросах необходимо использовать алиасы.
  9. Подзапросы SELECT должны заключаться в круглые скобки.
  10. Для подстановки даты в поля запроса можно использовать функцию «Родитель временных объектов».DateToString. В качестве параметра ф-ция получает значение типа FT_Date и возвращает строковое значение даты в формате ODBC { ts 'yyyy-mm-dd hh:mm:ss[.fff] '}.
  11. В качестве алиаса запрещено использовать «ts» (см. п.9).
  12. Во избежание неоднозначной интерпретации не рекомендуется назначать различным элементам запроса одинаковые алиасы.
  13. Парсер умеет правильно разбирать имена подобъектов. Синтаксис конструкции: «<Имя объекта>.<Имя подобъекта>». Например, «Товарный документ. Расшифровка спецификации».
  14. Парсер разбирает имена пользовательских функций(UDF) ConvertSum(пересчет сумм) и ConvertValue(пересчет количеств). Так как пользовательские функции SQL Server’а требуют указания имени пользователя базы, то для этого добавлен шаблон $RSDBUSERNAME$. Пример использования: … $RSDBUSERNAME$.ConvertSum(…) …

Выполнение запроса производится вызовом «Родитель временных объектов».RunQuery. Параметры:

  1. Строка запроса[in, required].

Для облегчения отладки и тестирования запросов имеется процедура «Родитель временных объектов».TestParsing. Процедура парсит запрос и возвращает прошедшие парсинг части исходного и результирующего запросов. Параметры:

  1. Строка запроса[in, required],
  2. Часть строки исходного запроса, прошедшая парсинг [out, required],
  3. Строка результирующего запроса [out, required].

Временные объекты с локальными метаданными (TypeInfo, TI)

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

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

Для того, чтобы временный объект создался с локальным TI, его имя должно начинаться с префикса «#». Все остальные действия по созданию объекта те же, что и описанные выше.

Локальные TI в отличие от глобальных (создаваемых для объектов без префикса «#») удаляются с сервера приложений при отсоединении от сервера клиентского приложения, их создавшего. Глобальные TI выгружаются только вместе с сервером приложений.

Временные объекты на глобальных временных таблицах

Механизм временных объектов позволяет использовать не только локальные временные таблицы (префикс имени таблицы #), но и глобальные (префикс ##). Глобальные временные таблицы разрешается использовать только в процессе разработки для отладки кода, заполняющего временные объекты. Выкладывать в репозиторий код, создающий временные объекты на глобальных таблицах, запрещено! У этого запрета есть объективные причины.

Как известно, временные таблицы MSSQL хранит в отдельной, специально обученной базе, tempdb. База эта общая для всех клиентов, работающих с SQL-сервером. Т.е. если на одном SQL-сервере крутится RS-Balance и 1C, то их временные таблицы будут лежать в одной кучке.

Для базы данных существует понятие уровня изоляции транзакций (transaction isolation level). Уровень изоляции описывает способ блокировок объектов базы и видимости данных, используемых разными транзакциями. Чтобы в транзакции могли участвовать таблицы из разных баз, эти базы должны иметь одинаковый уровень изоляции.

По умолчанию все базы данных, в том числе и tempdb, имеют уровень изоляции READ COMMITTED. Для базы данных RS-Balance 3 было принято решение использовать уровень изоляции SNAPSHOT, как наиболее удовлетворяющий требованию снижения количества взаимоблокировок. Этот уровень изоляции устанавливается явным образом при установке или обновлении RS-Balance. Таким образом транзакции с участием таблиц базы баланса и tempdb становятся невозможными. На что мы периодически натыкаемся: SQL-сервер ругается на несоответствие уровня изоляций, tempdb должна иметь уровень изоляции SNAPSHOT.

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

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

Просмотр текущего уровня изоляции БД:

Select name, snapshot_isolation_state, snapshot_isolation_state_desc from sys.databases

Изменение текущего уровня изоляции БД:

ALTER DATABASE <Имя БД> SET ALLOW_SNAPSHOT_ISOLATION ON


Тоже дает какую-то информацию (надо уточнять):

USE <Имя БД>
DBCC USEROPTIONS

Может быть изменено:

ALTER DATABASE <Имя БД> SET READ_COMMITTED_SNAPSHOT ON

Пример реализации

 /************************************************************************************
  FILE         :     COrptCompositionStepRevSheet18.mac 
 
  COPYRIGHT    :     R-Style Softlab, 2004
 
  DESCRIPTION  :     Оборотная ведомость по дате
 
  PROGRAMMED BY:     Oleg Ovcharenko
 
  CREATION DATE:     01.10.2004
 ************************************************************************************/
 
 cpwin;
 
 class (CReportCompositionStep) CCOrptCompositionStepRevSheet18(_dsFuncReport : Object)
 
   InitCReportCompositionStep(_dsFuncReport);
 
   '''// создать строку для прихода или расхода'''
   macro AddSumString(_dBeginDate, _dEndDate,
                      _sOrgIds, _sOfficeIds, _sStoreHouseIds, _sMOLIds,
                      _nCurrencyType, _bIsIncome)
     var sResult = "";
     var sSumFieldName;
     if(_nCurrencyType == null)
       sSumFieldName = "\"Сумма в базовой валюте\""; 
     else
       sSumFieldName = "\"Сумма в валюте\"";       
     end;
 
     if(_dBeginDate == null)
       sResult = "SELECT 0 AS DateReg, ";  // создание фиктивной записи для начального остатка
     else
       sResult = "SELECT synWareDoc.\"Дата регистрации\" AS DateReg, ";   
     end;
 
     if(_bIsIncome == true)        // приход
       sResult = sResult + "SUM(synWareDoc." + sSumFieldName + ") AS InCome, 0 AS Outcome ";
     else                          // расход
       sResult = sResult + "0 AS Income, SUM(synWareDoc." + sSumFieldName + ") AS OutCome ";
     end;
 
     sResult = sResult + "FROM \"Товарный документ\" synWareDoc " +
                         " WHERE ";
 
     if(_dBeginDate == null)
       sResult = sResult + "(synWareDoc.\"Дата регистрации\" < " + _dEndDate + ") ";
     else
       sResult = sResult + "(synWareDoc.\"Дата регистрации\" >= " + _dBeginDate + ") AND " +
                           "(synWareDoc.\"Дата регистрации\" <= " + _dEndDate + ") ";
     end;
 
     if(_nCurrencyType != null)  // отбираем по валюте
       sResult = sResult + " AND (synWareDoc.\"Валюта\" = " + _nCurrencyType +") ";
     end;
 
     // условие по организациям
     if(_sOrgIds != null)
       if(_bIsIncome == true)
         sResult = sResult + " AND (synWareDoc.\"Куда организация\" ";
       else
         sResult = sResult + " AND (synWareDoc.\"Откуда организация\" ";
       end;
       if(_sOrgIds != "")
         sResult = sResult + " IN (" + _sOrgIds + ")) ";
       else
         sResult = sResult + " IS NULL) ";
       end;
     end;
 
     // условие по подразделениям
     if(_sOfficeIds != null)
       if(_bIsIncome == true)
         sResult = sResult + " AND (synWareDoc.\"Куда подразделение\" ";
       else
         sResult = sResult + " AND (synWareDoc.\"Откуда подразделение\" ";
       end;
       if(_sOfficeIds != "")
         sResult = sResult + " IN (" + _sOfficeIds + ")) ";
       else
         sResult = sResult + " IS NULL) ";
       end;
     end;
 
     // условие по складам
     if(_sStoreHouseIds != null)
       if(_bIsIncome == true)
         sResult = sResult + " AND (synWareDoc.\"Куда склад\" ";
       else
         sResult = sResult + " AND (synWareDoc.\"Откуда склад\" ";
       end;
       if(_sStoreHouseIds != "")
         sResult = sResult + " IN (" + _sStoreHouseIds + ")) ";
       else
         sResult = sResult + " IS NULL) ";
       end;
     end;
 
     // условие по МОЛам
     if(_sMOLIds != null)
       if(_bIsIncome == true)
         sResult = sResult + " AND (synWareDoc.\"Куда МОЛ\" ";
       else
         sResult = sResult + " AND (synWareDoc.\"Откуда МОЛ\" ";
       end;
       if(_sMOLIds != "")
         sResult = sResult + " IN (" + _sMOLIds + ")) ";
       else
         sResult = sResult + " IS NULL) ";
       end;
     end;
 
     sResult = sResult + " GROUP BY synWareDoc.\"Дата регистрации\" ";
     return sResult;
   end;
 
   // выполнить
   macro Execute(_oInputParams : CReportInputParams)
     Execute(_oInputParams);
 
     var sOrganization, sOffice, sStoreHouse, sMOL;
     sOrganization = GetListFromArray(_oInputParams.GetValue("array(Организация)"), "", ",");
     if(sOrganization == null)
       sOrganization = "";
     end;
 
     if(_oInputParams.GetValue("string(Подразделение)") != "все")
       sOffice = GetListFromArray(_oInputParams.GetValue("array(Подразделение)"), "", ";");
       if(sOffice == null)
         sOffice = "";
       end;
     end;
     if(_oInputParams.GetValue("string(Склад)") != "все")
       sStoreHouse = GetListFromArray(_oInputParams.GetValue("array(Склад)"), "", ";");
       if(sStoreHouse == null)
         sStoreHouse = "";
       end;
     end;
     if(_oInputParams.GetValue("string(МОЛ)") != "все")
       if(_oInputParams.GetValue("МОЛ") != null)
         sMOL = _oInputParams.GetStringValue("МОЛ");
       else
         sMOL = "";
       end;
     end;
 
     var sXML;
     sXML = "<Comment>Выходной объект для Оборотной ведомости по дате</Comment>" + 
       "<Field Number ='1' Name='Идентификатор' Type='FT_Int32' Flags='0x1b'   DBCode = 'ID'/>" +
       "<Field Number ='2' Name='Дата'          Type='FT_Date'  Flags='0x8009' DBCode = 'DateReg'/>" +
       "<Field Number ='3' Name='Нач. остаток'  Type='FT_Money' Flags='0x5'    DBCode = 'BegRemains'>" +
       "<DefaultValue>0.0000</DefaultValue>" +
       "</Field>" +
       "<Field Number ='4' Name='Приход'        Type='FT_Money' Flags='0x5'    DBCode = 'InCome'/>" +
       "<Field Number ='5' Name='Расход'        Type='FT_Money' Flags='0x5'    DBCode = 'OutCome'/>" +
       "<Field Number ='6' Name='Кон. остаток'  Type='FT_Money' Flags='0x5'    DBCode = 'EndRemains'/>" +
       "<Field Number ='7' Name='Дельта'        Type='FT_Money' Flags='0x5'    DBCode = 'SumDelta'/>";
 
     '''var dsRootTmp = GetDS("Родитель временных объектов", null, 1);'''
     '''dsRootTmp.RSObject.Run("AddTmpChildObj",'''
                            '''"Объект Оборотная ведомость по дате", "#rptRevSheetDate", sXML,'''
                            '''"78D85683-75C5-41BF-8E7F-6C007241BB05");'''
 
     var nCurrencyType = _oInputParams.GetValue("Валюта");
     '''var sDateFrom = dsRootTmp.RSObject.Run("DateToString", _oInputParams.GetValue("Период с"));'''
     var sDateTo       = dsRootTmp.RSObject.Run("DateToString", _oInputParams.GetValue("Период по"));
 
     var sQuery = "-- Отчет: Оборотная ведомость по дате. \n" +
       "INSERT INTO \"Объект Оборотная ведомость по дате\" " +
         "(\"Дата\", \"Приход\", \"Расход\", \"Дельта\") " +
       "SELECT DateReg, SUM(InCome), SUM(OutCome), SUM(InCome) - SUM(OutCome) " +
       "FROM ( " +
     // создать фиктивную строку для начального остатка
         "SELECT 0 AS DateReg, 0 AS InCome, 0 AS OutCome " +
         "FROM \"Товарный документ\" synWareDoc" +
 
       " UNION ALL " +
     // приход на начало
       AddSumString(null, sDateFrom, sOrganization, sOffice, sStoreHouse, sMOL, nCurrencyType, true) +
 
     // расход на начало
       "\n UNION ALL " +
       AddSumString(null, sDateFrom, sOrganization, sOffice, sStoreHouse, sMOL, nCurrencyType, false) +
 
     // приход
       "\n UNION ALL " +
       AddSumString(sDateFrom, sDateTo, sOrganization, sOffice, sStoreHouse, sMOL, nCurrencyType, true) +
 
     // приход
       "\n UNION ALL " +
       AddSumString(sDateFrom, sDateTo, sOrganization, sOffice, sStoreHouse, sMOL, nCurrencyType, false)+
 
       ") mytbl " +
       "GROUP BY DateReg " +
       "";
 
     // тестовое окно
     var sIn = "";  
     var sOut = "";  
     '''dsRootTmp.RSObject.Run("TestParsing", sQuery, @sIn, @sOut);'''
     var sss = sIn + "\n---------------------------------------\n" + sOut;
     MsgBox(sss);
 
     '''dsRootTmp.RSObject.Run("RunQuery", sQuery);'''
 
     var dsStatObj = GetFullDS("Объект Оборотная ведомость по дате", 100);
     _oInputParams.SetValue("Выходной объект", dsStatObj.RSObject);
   end;
 end;

Новый RSQL-парсер

Допущения

При написании SQL-запроса можно не использовать псевдонимы объекта лишь в том случае, если имена полей также не будут использовать псевдонимы. Это вызвано тем, что нет возможности по имени таблицы определить имя объекта созданного на этой таблице. Например whCard может означать как "Картотека ТМЦ", так и "Картотека складского учета" и "Картотека по свойствам и местам хранения".

Отличия

Основные видимые отличия от прежнего парсера:

 SELECT "Код" FROM "Номенклатура"
 SELECT "Код2" FROM "Номенклатура"
Некорректная лексема <Код2> 1:8 Неопределенное поле "Код2"
 SELECT "Код" FROM "Номенклатура2"
Некорректная лексема <Номенклатура2> 1:19 Объекта с именем "Номенклатура2" нет.
 SELECT "Номенклатура"."Код" FROM "Номенклатура"

Пример

Из вышеприведенного примера можно убрать псевдоним synWareDoc. Тогда RSQL-запрос будет выглядеть так:

-- Отчет: Оборотная ведомость по дате. 
 INSERT INTO "Объект Оборотная ведомость по дате"("Дата", "Приход", "Расход", "Дельта")
 SELECT DateReg, SUM(InCome), SUM(OutCome), SUM(InCome) - SUM(OutCome)
 FROM (
       SELECT 0 AS DateReg,
              0 AS InCome,
              0 AS OutCome
       FROM "Товарный документ"
       UNION ALL
 ...
       UNION ALL
       SELECT "Дата регистрации" AS DateReg ,
              0 AS Income ,
              SUM("Сумма в базовой валюте") AS OutCome
       FROM "Товарный документ"
       WHERE ("Дата регистрации" >= {ts '2005-01-12 00:00:00'}) AND
             ("Дата регистрации" <= {ts '2005-12-12 00:00:00'}) AND
             ("Откуда организация" IN (5006, 5012, 5014)) AND
             ("Откуда подразделение" IS NULL) AND
             ("Откуда склад" IS NULL) AND
             ("Откуда МОЛ" IS NULL)
       GROUP BY "Дата регистрации"
      ) mytbl
 GROUP BY DateReg

Соответствующий SQL-запрос будет иметь вид:

 INSERT INTO #rptRevSheetDate ( DateReg , InCome , OutCome , SumDelta ) 
 SELECT DateReg , SUM ( InCome ) , SUM ( OutCome ) , SUM ( InCome ) - SUM ( OutCome ) 
 FROM ( 
       SELECT 0 DateReg , 
              0 InCome , 
              0 OutCome 
       FROM cowWareDoc 
       UNION ALL
 ...
       UNION ALL
       SELECT DateReg DateReg , 
       0 Income , 
       SUM ( SumBase ) OutCome 
       FROM cowWareDoc 
       WHERE ( DateReg >= { ts '2005-01-12 00:00:00' } ) AND 
             ( DateReg <= { ts '2005-12-12 00:00:00' } ) AND 
             ( SourcOrg IN ( 5006 , 5012 , 5014 ) ) AND 
             ( SourcOffice IS NULL ) AND 
             ( SourcWareh IS NULL ) AND 
             ( SourcOwner IS NULL ) 
       GROUP BY DateReg 
      ) mytbl 
 GROUP BY DateReg

Переключение между парсерами

Для переключения между старым и новым парсером используется настройка сервера OldRSQLParser.

Методы объектов, использующие парсер

Парсер используется в следующих методах объектов:

Представление грида временного объекта

Различаются параметры сохранения/чтения представлений грида для объектов с локальным (имя объекта начинается с #) и глобальным TI.
Для объектов с локальным TI представление идентифицируется с помощью LayoutName грида и идентификатора пользователя. LayoutName по умолчанию равен имени грида в ресурсе LBR.
Для объектов c глобальным TI к идентификации представления дополнительно добавляется GUID временного объекта.
Для объектов с локальным TI могут возникать конфликты при работе с представлениями - если разные объекты отображаются в гриде с одним и тем же LayoutName. Когда второй объект считывает представление первого. В этом случае конфликт разрешается путем выбора из представления только тех параметров, которые можно применить к данному объекту.

Личные инструменты
Пространства имён
Варианты
Действия
Навигация
Для разработки
Инструменты