Основная страница

Технологические вопросы


Обработка ошибочных ситуаций во встроенном языке системы 1С:Предприятие  7.7

Во встроенный язык системы 1С:Предприятие 7.7 внесена возможность обработки ошибочных ситуаций. В предыдущих версиях системы 1С:Предприятие любая ошибка, происшедшая при выполнении модулей встроенного языка приводила к завершению выполнения модуля и выдаче в окно сообщений информации о характере ошибки и модуле, в котором она произошла. При этом разработчик конфигурации не имел возможности вмешаться в процесс обработки ошибочной ситуации и предусмотреть некоторые действия, которые могут нейтрализовать последствия ошибки и позволить продолжить выполнение модуля. Особенно неприятны ситуации, когда из-за несущественных поводов прекращается выполнение длительных процедур, после чего их приходилось начинать сначала. Примером такой ситуации может послужить обработка, выполняющая обход и обновление некоторого реквизита большого числа элементов справочника в случае, если в процессе работы будет произведена попытка обновить реквизит заблокированный другим пользователем. Неприятны также ситуации, когда конфигурации, использующие внешние по отношению к системе 1С:Предприятие программные средства через механизмы OLE Automation не могли произвести проверку наличия установленных на компьютере пользователя необходимых программных средств. Примером для такого случая может послужить поведение отчета, выводящего результаты через OLE Automation в таблицу MS Excel, в условиях, когда MS Excel на компьютере пользователя отсутствует.

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

Попытка

    // Некоторые действия

Исключение

    // Обработка исключительной (ошибочной) ситуации)

КонецПопытки

Суть в следующем: если при выполнении последовательности операторов <// Некоторые действия> происходит ошибка, то выполнение оператора прекращается и управление передается на первый оператор последовательности <// Обработка исключительной (ошибочной) ситуации)>. После завершения выполнения данной последовательности управление получает первый оператор, следующий за КонецПопытки. В случае, если при выполнении <// Некоторые действия> ошибок не произошло, то управление, минуя <// Обработка исключительной (ошибочной) ситуации)> также попадает на первый оператор, следующий за КонецПопытки. Конструкции Попытка…Иключение…КонецПопытки могут быть вложенными, при этом для передачи управления из более внутреннего обработчика исключительной ситуации в более внешний служит оператор ВызватьИсключение. В случае, если оператор ВызватьИсключение будет выполнен в самом внешнем обработчике ошибки, то выполнение модуля будет прекращено и сообщение об ошибке будет выдано в окно сообщений, как и в случае полного отсутствия обработчиков ошибок. Для получения текста описания ошибки внутри последовательности операторов <// Обработка исключительной (ошибочной) ситуации)> служит встроенная функция ОписаниеОшибки(). Более подробно о механизме обработки исключительных ситуаций можно прочитать в книге "1С:Предприятие 7.7. Описание встроенного языка. Часть 1.".

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

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

Блокировка объектов базы данных

В данном разделе рассматриваются различные стратегии и логика механизмов блокировок базы данных системы 1С:Предприятие 7.7, используемых для обеспечения многопользовательского режима работы. Как известно, все варианты системы 1С:Предприятие 7.7 способны работать с базами данных в формате .DBF/.CDX. Кроме того, имеются варианты поставки - 1С:Предприятие 7.7 для SQL, способные работать с базами данных, размещаемыми в среде серверов баз данных Microsoft SQL Server 6.5/7.0. Естественно, что для этих двух форматов баз данных используются совершенно разные механизмы доступа к данным. Но при этом логика работы с базой данных в общем остается неизменной. Соответственно, все, о чем будет рассказано в данном разделе является справедливым для обоих возможных форматов построения баз данных системы 1С:Предприятие 7.7.

Блокировки, осуществляемые в базе данных системы 1С:Предприятие 7.7 можно разделить на две группы:

Табличные (транзакционные) блокировки , как следует из названия выполняются на уровне таблиц и служат для обеспечения взаимодействия транзакций, выполняемых несколькими экземплярами системы 1С:Предприятие в одной информационной базе. Блокировки данного вида автоматически устанавливаются и снимаются программами системы 1С:Предприятие в процессе отработки транзакций и предназначены для обеспечения неизменности считанных данных в процессе выполнения транзакции. Имеются два уровня табличных блокировок "на чтение" и "на запись". Различаются эти два уровня тем, что "на чтение" одна и та же таблица может быть заблокирована более чем одним экземпляром системы 1С:Предприятие, в то время как блокировка "на запись" является исключительной, то есть "на запись" таблица может быть заблокирована только одним экземпляром системы.

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

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

Установка табличных блокировок выполняются с таймаутом. Это означает, что в случае неудачной попытки установить блокировку таблицы сразу, попытки будут повторяться в течение некоторого интервала времени. Этот интервал может устанавливаться пользователем с помощью параметра "Время ожидания захвата таблиц Базы Данных", который доступен через диалог установки параметров системы 1С:Предприятие (пункт меню <Сервис/Параметры>, страница диалога <Общие>).

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

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

В более ранних чем 7.7 версиях системы 1С:Предприятие механизм "пессимистических" блокировок использовался только при редактировании тех или иных объектов базы данных и никак не мог быть задействован из встроенного языка. В версии 7.7 введена возможность явной блокировки объектов из встроенного языка. Данная возможность доступна только для объектов, создаваемых посредством обращения к функции СоздатьОбъект . Соответственно, таким способом могут быть заблокированы такие объекты базы данных как элементы справочника, счета бухгалтерского учета и документы. Блокировка отдельных объектов осуществляется с помощью обращения к методу Блокировка(<ВклВыкл>). Необязательный параметр <ВклВыкл> обозначает действие, которое надо выполнить: 1 -  заблокировать объект базы данных, 0 -  разблокировать. Метод возвращает значение, показывающее результат выполнения операции: 1 -  операция выполнена

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

Спр = СоздатьОбъект("Справочник.Товары");

Спр.ВыбратьЭлементы();

Пока Спр.ПолучитьЭлемент() = 1 Цикл

      Пока Спр. Спр.Блокировка(1) = 0 Цикл

            Если Вопрос("Элемент справочника заблокирован! Повторить попытку?",

                  "Да+Нет") = "Нет" Тогда

                  Возврат;

            КонецЕсли;

      КонецЦикла;

      // Модифицируем реквизиты элемента справочника

      Спр.Записать();  // Записываем измененный элемент справочника

КонецЦикла;

Следует обратить внимание, что после записи модифицированного элемента справочника не производится снятия блокировки в явном виде. В этом нет необходимости, так как блокировка автоматически снимается при переходе к следующему элементу с помощью метода ПолучитьЭлемент().

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

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

Действия Экземпляра 1 Действия Экземпляра 2 Результат
ПолучитьЭлемент()    ОК 
  ПолучитьЭлемент()  ОК 
Блокировка(1)     
  Записать()       Ошибка!
Записать()       ОК 

Из приведенной таблицы видно, что Экземпляр 2 не смог произвести запись элемента справочника, заблокированного Экземпляром 1. Сработал механизм "пессимистической" блокировки. Аналогично, если бы оба экземпляра системы 1С:Предприятие пользовались первым вариантом обработки, то Экземпляр 2 не смог бы заблокировать элемент справочника.

А теперь представим, что оба экземпляра системы 1С:Предприятие пользуются вторым вариантом обработки. Тогда "встреча" на одном и том же элементе справочника может пройти следующим образом:

Действия Экземпляра 1 Действия Экземпляра 2 Результат
  ПолучитьЭлемент()  ОК 
ПолучитьЭлемент()    ОК 
Записать()         Ошибка!
  Записать()     ОК 

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

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

Вычисление логических выражений в операторах встроенного языка

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

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

  Предположим, имеется процедура, предназначенная для обработки некоторого реквизита справочника или документа. Тип данного реквизита не определен, а процедура может вызываться для любого значения реквизита вне зависимости от его типа. Процедура может иметь вид:

Процедура Обработать(Об)

    Если (ТипЗначенияСтр(Об) = "Справочник") И (Об.Вид() = "Товары") Тогда

        // Некоторые действия

    КонецЕсли;

    ...

КонецПроцедуры

Если в качестве значения параметра, передаваемого в данную процедуру, будет фигурировать элемент справочника любого вида, то процедура будет работать нормально, но если в качестве параметра будет передано значение типа "Число" или "Дата", то выполнение процедуры будет аварийно завершено. В логическом выражении, используемом в операторе 'Если' только составляющая ТипЗначенияСтр(Об) = "Справочник" будет корректно функционировать независимо от типа передаваемого параметра, а составляющая Об.Вид() = "Товары" сможет нормально работать только в том случае, если в качестве параметра в процедуру передано значение агрегатного типа и для данного агрегатного типа определен метод Вид(). Дело в том, что при вычислении логических выражений встроенный язык системы 1С:Предприятие 7.х сначала вычисляет элементарные логические выражения (операции сравнения), а затем производит вычисление логического выражения в целом (операции И/ИЛИ/НЕ).

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

Процедура Обработать(Об)

    Если ТипЗначенияСтр(Об) = "Справочник" Тогда

        Если Об.Вид() = "Товары" Тогда

            // Некоторые действия

        КонецЕсли

    КонецЕсли

    ...

КонецПроцедуры

В данном случае порядок вычисления логических выражений в операторах Если выражен в явном виде и выражение Об.Вид() = "Товары" будет вычисляться только в том случае если условие ТипЗначенияСтр(Об) = "Справочник" окажется истинным и ошибки при выполнении процедуры не произойдет при любом значении параметра.

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

Особенности применения предопределенных процедур встроенного языка

Во встроенном языке системы 1С:Предприятие 7.x предусмотрен ряд системных предопределенных процедур При..., таких как "ПриЗаписи", "ПриУдаленииДокумента", "ПриУдаленииЭлемента", "ПриЗаписиКонстанты", "ПриОтменеПроведенияДокумента" и т. п., определяемых в различных модулях конфигурации и вызываемых системой при выполнении соответствующих действий. Назначение указанных процедур состоит в том, чтобы специалист по конфигурированию мог предусмотреть необходимые проверки при интерактивном выполнении соответствующих операций, и, в случае необходимости, имел возможность запретить их выполнение.

При этом следует учитывать следующие особенности данных процедур:

1. Указанные предопределенные процедуры не связаны непосредственно с действиями, при выполнении которых они вызываются, а сам вызов производится только при интерактивном выполнении указанных действий. Например, процедура "ПриУдаленииДокумента" будет вызвана в том случае, когда удаление документа будет инициировано "нажатием кнопки" в форме журнала. В то же время вызов этой предопределенной процедуры не будет производиться, если удаление документа производится из какого-либо модуля встроенного языка (например, из некоторой обработки).

2. Вызовы указанных предопределенных процедур не объединены с выполняемым действием единой транзакцией. Это означает, что в случае интерактивного удаления документа, само удаление документа выполняется в транзакции, отдельной от действий, которые могут выполняться в процедуре "ПриУдаленииДокумента". И если в процедуре "ПриУдаленииДокумента" действия будут выполняться в раках одной, явно определенной в процедуре транзакции, то все равно приходится говорить о двух транзакциях:

  - удаление документа;

  - действия, выполняемые в процедуре "ПриУдаленииДокумента"

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

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

Заметим, что описанные выше особенности предопределенных процедур не распространяются на предопределенные процедуры "ОбработкаПроведения" и "ОбработкаУдаленияПроведения". Эти предопределенные процедуры вызываются непосредственно в транзакции проведения (отмены проведения) и выполняемые в них алгоритмы логически связанны с самим выполняемым действием. Кроме того, в отличие от других предопределенных процедур эти предопределенные процедуры выполняются и в случае проведения (отмены проведения) средствами встроенного языка.

Сохранение (восстановление) значений в строку

         В 1С:Предприятии существует несколько способов, позволяющих преобразовать значение к строковому виду и восстановить его обратно из строки.

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

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

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

Какие значения преобразуются в строку.

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

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

         Значения других типов используемых во встроенном языке 1С:Предприятия, но не хранящиеся в информационной базе (например, "Таблица" или "Запрос") не могут быть преобразованы к строке.

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

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

Способы преобразования к строке.

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

Внутренний формат.

Для преобразования к строковому виду (и обратно) во внутреннем формате используются следующие функции:

- ЗначениеВСтрокуВнутр / ЗначениеИзСтрокиВнутр;

- ЗначениеВФайл / ЗначениеИзФайла - параметр "Формат" =1;

- СохранитьЗначение / ВосстановитьЗначение.

Кроме того, во внутреннем строковом формате хранятся значения расшифровок табличного документа.

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

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

      Строки, полученные преобразованием значений к строке во внутреннем формате нельзя хранить в информационной базе. Прежде всего, это приведет к нарушению работы механизма контроля ссылочной целостности. Также, это может повлиять на работу компоненты "Управление распределенными данными ИБ".  Разумеется, такое хранение значений, также не позволит системе оптимизировать обращение к данным при использовании версий 1С:Предприятия для SQL. Заметим, что хранение в информационной базе значений преобразованных в строку нарушает идеологию 1С:Предприятия и затрудняет отладку и модификацию конфигураций.

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

Внешний формат

Для преобразования к строковому виду во внешнем формате используются

следующие функции:

- ЗначениеВСтроку / ЗначениеИзСтроки;

- ЗначениеВФайл / ЗначениеИзФайла - параметр "Формат" =0.

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

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

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

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

Automation нельзя.

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

      Заметим, что преобразование к строке и обратно значений типа "число", "строка" и "дата" происходит однозначно (гарантированно) в обоих форматах, так как эти значения не зависят от конфигурации. В качестве примера такого сохранения в методической конфигурации в обработке "НастройкаПрописи" выполняется сохранение в файле строк, используемых для вывода чисел, дат и периодов прописью.

Работа со значениями агрегатных типов во встроенном языке

При работе со значениями агрегатных типов во встроенном языке системы 1С:Предприятие следует учитывать некоторые особенности, которые не всегда являются очевидными.

Каждое значение агрегатного типа в системе 1С:Предприятие включает две составляющие:

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

выполнения оператора

A = B;

при условии, что переменная B имела значение агрегатного типа и уже имела ссылку на объект доступа, переменные A и B будут ссылаться на один и тот же объект доступа.  В отличие от базовых типов (число, строка, дата), для которых при присваивании копируется само значение, при присваивании агрегатных типов копируется не объект доступа, а только ссылка на него.

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

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

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

Тов = Док.Товар;   // Объект доступа еще не создан, при условии, что ранее не было обращений к атрибутам и методам;

Тов2 = Док.Товар;  // Аналогично

Цена = Тов.Цена;   // Для переменной Тов создается объект доступа

Цена2 = Тов2.Цена; // Для переменной Тов2 создается объект доступа. Тов и Тов2 ссылаются на разные объекты доступа

Тов3 = Тов;        // Тов и Тов3 ссылаются на один объект доступа

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

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

Тов = 0;   // Удалена ссылка на объект доступа

Тов2 = 0;  // Уничтожен первый объект доступа

Тов3 = 0;  // Уничтожен второй объект доступа

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

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

Цена = Док.Товар.Цена;

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

Наимен = Док.Товар.Наименование;

Цена = Док.Товар.Цена;

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

Тов = Док.Товар;  // Присваивается реквизит документа. Объект доступа еще не создан

Наимен = Тов.Наименование; //  Для переменной Тов создается объект доступа

Цена = Тов.Цена;  // Используется созданный ранее объект доступа

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

Значения типов, соответствующих объектам информационной базы во встроенном языке

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

  - значения, полученные путем вызова системной функции СоздатьОбъект

  - значения полученные из реквизитов форм и атрибутов объектов информационной базы

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

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

  Но несмотря на такие существенные различия оба описанных варианта значений одинаковы во многих проявлениях. Рассмотрим пример:

Спр1 = СоздатьОбъект("Справочник.Товары");

Спр2 = Док.Товар;

Переменные Спр1 и Спр2 содержат значения двух описанных выше видов. Для этих переменных способ доступа к атрибутам справочника производится одним и тем же способом. Многие методы объекта типа Справочник могут применяться как к Спр1, так и Спр2. Функции ТипЗначения() и ТипЗначенияСтр(), будучи  примененными к Спр1 и Спр2 дадут одинаковые результаты. Многие методы встроенного языка также не различают какого вида значение передано им в качестве параметра: точное значение объекта или спозиционированная выборка.

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

1.

Спр1 = СоздатьОбъект("Справочник.Товары");

Спр1.ВыбратьЭлементы();

Пока Спр1.ПолучитьЭлемент() = 1 Цикл

    Обработать(Спр1);

КонецЦикла;

2.

Спр2 = Док.Товар;

Обработать(Спр2);

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

Спр1 = СоздатьОбъект("Справочник.Товары");

Спр1.ВыбратьЭлементы();

Пока Спр1.ПолучитьЭлемент() = 1 Цикл

    Обработать(Спр1.ТекущийЭлемент());

КонецЦикла;

Функция ТекущийЭлемент() в качестве значения возвращает точное значение элемента справочника, на который спозиционирована выборка. А если функция ТекущийЭлемент() применяется к переменной, значением которой является уже точное значение элемента справочника, эта функция вернет само это значение. Так что равноценным вариантом решения показанной в примере проблемы было бы, если  для выполнения действий процедура Обработать() использовала бы не сам переданный параметр, а значение некоторой переменной (например, Спр), значение которое получила бы из переданного параметра (Парам) следующим способом:

Спр = Парам.ТекущийЭлемент();

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

Обработать(Спр1.ТекущийЭлемент());

Аналогичные соображения справедливы для объектов типа документ и счет бухгалтерского учета. Для документов аналогом функции ТекущийЭлемент() является функция ТекущийДокумент(), а для счетов  бухгалтерского учета - ТекущийСчет().

Выбор разрядности для д