Встроенный язык

Типы данных и операторы

Переменные

Динамическая типизация.

а = -1;
а = "Один";
Сообщить(а);
//"Один"

ТипЗнч(элмас) - вывести тип переменной.

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

Перем <Имя переменной 1> [Экспорт]

Типы данных и преобразования типов

Примитивные типы данных

Тип Описание
Null

Исключительно для определения отсутствующего значения при работе с базой данных.

Неопределено (Undefined)

Пустое значение, не принадлежащее ни к одному другому типу.

а = Неопределено;
б = ?(а = Неопределено, 0, 1);//б = 0

Прямое преобразование в булево: нельзя

При сравнении любой тип не равен Неопределено

а = 0;
б = ?(а = Неопределено, 0, 1);//б = 1
Число

Определены основные арифметические операции. Максимальная разрядность 38 знаков. Разделитель точка. 32 знака.

Прямое преобразование в булево: любое ненулевое Истина, 0 Ложь

Преобразование в строку: Строка()

Строка

Формат Unicode произвольной длины. В двойных кавычках. Многостроковый режим через |

Прямое преобразование в булево: нельзя

а = "";
б = ?(а, 0, 1); //вызовет ошибку

Преобразование в число:

Ч1 = Число(СтрокаЧ1);//вызовет исключение при невозможности

 Преобразование в дату: 

Дата("20211231123456"); //YYYYMMDDHHMMSS
Дата("2021", "12", "24", "12", "34", "56");
Дата

Строка цифр, заключенная в одинарные кавычки вида: 'ГГГГММДДччммсс'

Прямое преобразование в булево: нельзя

Контроль заполненности: Перем.ЗначениеЗаполнено()

Пустая дата - Дата(1,1,1)

Булево

Значения данного типа имеют два значения Истина и Ложь

Тип

Используются для идентификации типов значений. Это необходимо для определения и сравнения типов.

Универсальные коллекции значений

Тип Описание
Массив

Аналог списка. Конструктор: 

м1 = Новый Массив; //массив нулевой длины
м2 = Новый Массив(<ФиксированныйМассив>); //создание массива из фиксированного массива
м3 = Новый Массив(10, 3); //мас. из 10 эл-тов, каждый из которых - мас. из 3 эл-тов

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

Количество
Найти - Если найден - индекс, иначе неопределено.
Очистить - Удаляет все значения из массива.
Удалить - удаляет указанный индекс
Структура

Аналог словаря. Ключи только строковые. Конструктор: 

ст1 = Новый Структура; //пустая
ст1 = Новый Структура("к1, к2", 1, 2) //структура с ключами к1, к2 и знач. 1 и 2

Доступ к элементу: 

а["к1"];
а.к1;

Перебор значений: 

а = Новый Структура("к1, к2", 1, 2);
Для каждого элмас из а Цикл
    Сообщить(элмас.Ключ + " " + элмас.Значение);
КонецЦикла;

Вставить(ключ, значение)
Количество()
Очистить() - удаляет все элементы
Свойство(Ключ, [НайденноеЗначение]) - безопасный поиск по ключу
Удалить(Ключ)

 

 

Соответствие Как структура, только ключ может быть любого типа.
Список значений Как массив + строковое описание (Представление), Пометка и Картинка
Таблица значений

Двумерная таблица. 

тз = Новый ТаблицаЗначений;//Создание таблицы
тз.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
//Имя — идентификатор колонки
//Заголовок — представление колонки в диалогах
//ТипЗначения — тип, может быть произвольного типа;
//Ширина — ширина колонки в диалогах;

найдКолонка = тз.Колонки.Найти("Наименование");//поиск колонки
Если найдКолонка = Неопределено Тогда
	Сообщить("Колонка не найдена!");
КонецЕсли;

//перебор колонок
Для каждого Колонка Из тз.Колонки Цикл 
    Сообщить(Колонка.Имя); 
КонецЦикла;

Вставить()	Вставляет новую колонку в указанную позицию коллекции
Добавить()	Добавляет новую колонку в конец коллекции
Количество()	Возвращает количество колонок в коллекции
Найти()	Ищет колонку в коллекции по имени
Очистить()	Удаляет все колонки из коллекции
Сдвинуть()	Сдвигает колонку влево или вправо
Удалить()	Удаляет колонку из коллекции
СтрокаТЧ = тз.Добавить();
СтрокаТЧ.Наименование = "Стул деревянный";
тз = СтрокаТЧ.Владелец();
тз.Удалить(тз.Индекс(СтрокаТЧ));

Для Каждого СтрокаТЧ Из тз Цикл
	ИндСтроки = тз.Индекс(СтрокаТЧ);
КонецЦикла;

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






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

Объекты


Респект и уважуха автору AlexO за разъяснение сущности взаимодействия в 1С ссылка на форум


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

Тип конфигурации ...Объект (например СправочникОбъект) - 

Поскольку переписывать лень, далее используется слово Объект в понимании 1С.

Внешних модулей нет. Использование процедур в разных проектах - только копирование/вставка. Придется смириться.

Обращение к свойствам через точку или <Объект>["имя свойства"]

Менеджер = Справочники["Менеджеры"];
Менеджер = Справочники.Менеджеры;

Обращение к методам - через точку. Дополнение: 

Категорический запрет на использование в запросах "двойного разъименования" (Объект.Свойство<содержащее СсылкуНаДругойОбъект>.СвойствоДругогоОбъекта) - только явное соединение таблиц через СОЕДИНЕНИЕ...

Условные операторы

?(<Логическое выражение>, <Выражение 1>, <Выражение 2>)   

а = Истина;
б = ?(а = Ложь, 0, 1);//б = 1

Если <Логическое выражение> Тогда
// Операторы
[ИначеЕсли <Логическое выражение> Тогда]
// Операторы
[Иначе]
// Операторы
КонецЕсли;

Разное

Выполнить(<Строка>);
Выполнить("Сообщить(а)");

Исполняет строковое представление команды.

Общая информация

В данном разделе предоставлена информация, максимально связанная только со встроенным языком 1С. Информация об остальных объектах языка представлена по необходимости.

Предварительная подготовка конфигурации.

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

Циклы и метки

В циклах могут использовать операторы Прервать; и Продолжить;

Цикл for:

Для <Имя переменной> = <Выражение 1> По <Выражение 2> Цикл
// Операторы
КонецЦикла;

Обход коллекции:

Для каждого <Имя переменной 1> Из <Имя переменной 2> Цикл
// Операторы
КонецЦикла;

Цикл While

Пока <Логическое выражение> Цикл
// Операторы
КонецЦикла;

В языке есть метки.

Перейти ~ВыходИзДвойногоЦикла;

~ВыходИзДвойногоЦикла:
//продолжение

 

 

 

 

 

 

 

 

Модули, директивы препроцессора и компиляции

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

Модули служат для хранения кода. Несколько регламентированных точек размещения модулей, однако точка размещения кода для решения конкретной задачи регламентирована на уровне "можно и здесь, а можно и где-то там", поэтому финальная точка размещения зависит от фазы луны в момент создания кода разработчиком. То есть правила вроде есть, но их можно не исполнять. Однако важный нюанс: в каждой точке размещения доступны разные глобальные переменные, поэтому при написании кода набор доступных переменных нужно обязательно уточнять. Часто в интернетах приводят код без указания размещения модуля, потом при вопросе "А у меня не работает" сначала пара страниц троллинга типа они пиздец какие охуевшие спецы, потом кто-то снисходит до лошары. Хотя данное разделение не несет практической цели для разработчика конфигурации кроме искусственного усложнения и скорее артефакт изначально упрощенной архитектуры. Как деление подпрограмм на процедуры и функции.

Интересная статья по модулям, однако есть ряд недосказанных моментов. 

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

Группа Размещение модулей Базовое назначение Подробное описание
Общие Конфигурация - Общие - Общие модули Хранение общего кода, доступного из остальных модулей. Настроить обработку событий нельзя.  В этой статье.
Модули конфигурации

Конфигурация - Свойства.

 

Модуль приложения
Модуль внешнего соединения
Модуль сеанса

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

Управление отображением и событиями платформы
Модули классов

Конкретный класс. 

 

Модуль формы
Модуль объекта
Модуль менеджера

События, связанные с конкретным классом. Например нажатие кнопки "Показать группы" в окне списка справочника Номенклатура. Объекты конфигурации

Структура модуля:
Раздел определения переменных - от начала текста модуля до первого оператора Процедура, Функция, или любого исполняемого оператора. Только операторы объявления переменных Перем.
Раздел процедур - от первого Процедура / Функция до любого исполняемого оператора вне тела описания процедур или функций.
Раздел основной программы - от первого исполняемого оператора вне тела последней процедуры или функции до конца модуля. Могут находиться только исполняемые операторы. Исполняется в момент инициализации модуля. Обычно в разделе
основной программы имеет смысл размещать операторы инициализации переменных какими-либо конкретными значениями, которые необходимо провести до первого вызова любой из процедур или функций модуля.

Свойства модуля:

Директивы препроцессора и компиляции

Есть два режима, определяются при создании конфигурации: на локальном ПК (файловый) и на сервере 1С (клиент-серверный вариант). Файловый вариант объединяет в себе и код клиента, и код сервера, поэтому смысла от деления кода при помощи директив препроцессора нет.

При запуске конфигурации на выполнение производится загрузка и компиляция конфигурации. Алгоритм компиляции: 

Директивы препроцессора

При компиляции блоки распределяются в соответствии с директивами. Для указания разрешения использования процедур и функций общих модулей и модулей объектов используют инструкции препроцессора. 
Синтаксис:

#Если <Логическое выражение> Тогда
#ИначеЕсли <Логическое выражение> Тогда
#Иначе
#КонецЕсли

<Логическое выражение> = [НЕ] <Символ препроцессора> [<Булева операция> [НЕ] <Символ препроцессора> [<Булева операция> [НЕ] <Символ препроцессора>]…]
   <Символ препроцессора> = {НаКлиенте | НаСервере | ТолстыйКлиентОбычноеПриложение | ТолстыйКлиентУправляемоеПриложение | Клиент | Сервер | ВнешнееСоединение }
   <Булева операция> = {И | ИЛИ}

Можно использовать И (AND), ИЛИ  (OR), НЕ (NOT) Регистр букв не имеет значения.

Области

#Область, #КонецОбласти Нужны только для визуального сворачивания блоков кода. Могут быть вложенными. 

#Область [<Имя области>]
#КонецОбласти 

Условия

#Если (#If), #Тогда (#Then), #ИначеЕсли (#ElsIf), #Иначе (#Else), #КонецЕсли (#EndIf) Можно организовывать выполнение различных процедур и функций на сервере приложения или на клиентском месте. Для того, чтобы процедура присутствовала и была вызвана на стороне сервера, фрагмент кода должен выглядеть следующим образом: 

#Если Сервер Тогда 
Процедура Проц1() Экспорт 
КонецПроцедуры 
#КонецЕсли 

Если блок #Если Сервер Тогда … #КонецЕсли включает только часть процедуры, то процедура будет присутствовать как на стороне клиента, так и на стороне сервера. Только на клиентской стороне она будет без той части, которая заключена в блок, поэтому результат выполнения процедуры может зависеть от того, где обрабатывается вызов этой процедуры.

Для выполнения на клиентском месте в обычном и управляемом режиме:

#Если НаКлиенте Тогда
#КонецЕсли

Точки исполнения

Инструкция препроцессора НаКлиенте определена для всех клиентских приложений. Для тонкой подстройки модуля под конкретное клиентское приложение дополнительно введены инструкции ТолстыйКлиентОбычноеПриложение, ТолстыйКлиентУправляемоеПриложение, ТонкийКлиент и ВебКлиент, которые определены в соответствующих приложениях.

В обычном клиенте в обычном и управляемом режиме доступны НаКлиенте, Клиент, ТолстыйКлиентОбычноеПриложение, ТолстыйКлиентУправляемоеПриложение , НаСервере, Сервер. 
В файловом варианте инструкции препроцессора #Если Сервер…, #Если Клиент…, #Если ТолстыйКлиентОбычноеПриложение или #Если ТолстыйКлиентУправляемоеПриложение… определены всегда, поэтому экземпляр кода будет присутствовать всегда.
В тонком клиенте доступны – ТонкийКлиент, НаКлиенте, Клиент.
На серверной части тонкого клиента – Сервер, НаСервере.
Во внешнем соединении – ВнешнееСоединение, НаСервере, Сервер.

Директивы компиляции

Каждая процедура и функция модуля формы, модуля команды и общего модуля управляемого приложения предваряется директивой компиляции, определяющей среду исполнения данной процедуры. Директива предваряется символом "&". 

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

&НаКлиенте — определяет клиентскую процедуру (функцию); исполняется в среде клиентского приложения. В такой процедуре доступен клиентский контекст формы и вызовы любых процедур модуля.

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

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

&НаКлиентеНаСервереБезКонтекста  — определяет процедуру (функцию), исполняемую в модуле формы на клиенте и на сервере, не имеющую доступа к контексту формы, данным формы, переменным, но имеющую доступ к процедурам и функциям общих модулей – серверных, не глобальных и серверных и клиентских одновременно. Сама процедура (функция) доступна для клиентский, серверных контекстных и неконтекстных процедур и функций модуля формы. Из серверных внеконтекстных методов формы допускается вызов серверных методов общих модулей; 

&НаКлиентеНаСервере — определяет процедуру (функцию), исполняемую в модуле команды, выполняемую на клиенте и на сервере, имеющую доступ к процедурам и функциям общих модулей – серверных, не глобальных и серверных и клиентских одновременно, не имеющую доступ к переменным. Сама процедура (функция) доступна для клиентских серверных процедур и функций модуля команды.

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

В модуле команды предопределенная процедура-обработчик ОбработатьКоманду должна предваряться директивой &НаКлиенте, так как выполнение команды происходит в клиентском приложении.

Модуль формы
  В модуле формы доступны директивы компиляции – &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста.
 Модуль команды
  В модуле команды доступны директивы компиляции – &НаКлиенте, &НаСервере, &НаКлиентеНаСервере.
 Общий модуль
  В общем модуле доступны директивы компиляции – &НаКлиенте, &НаСервере.

Общие модули.

Описание подпрограмм, вызываемых из различных мест. Для доступности подпрограмм извне необходимо ключевое слово Экспорт. То есть модули-то общие, но есть нюанс.

Даже при средней сложности конфигурации, подпрограммы нужно группировать в разные Общие модули. Для удобства имена Общих модулей должны отражать содержание описываемых в них процедур. При создании Общего модуля, правилом хорошего тона считается не указывать директивы компиляции. Т.е. доступность процедур и функций должна определяться свойствами самого модуля. При таком подходе в отдельных Общих модулях будут располагаться клиентские процедуры, и в отдельных Общих модулях – процедуры серверные. В названиях общих модулей рекомендуется это указывать. Например: РегламентныеПроцедурыСервер, РегламентныеПроцедурыКлиент.

Нельзя описывать глобальные переменные модуля и раздел основной программы. Т е все внешние переменные должны передаваться в подпрограммы извне.

Доступность модулей зависит от типа приложения и режима работы (Клиент, Сервер).

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

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

Подпрограммы

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

Общие определения:

Знач - Следующий за ним параметр передается по значению. По умолчанию параметр процедуры передается по ссылке.

<Парам1>, ..., <ПарамN> - Список формальных параметров, разделяемых запятыми, может быть пуст.

=<ДефЗнач>- Установка значения параметра по умолчанию.

Экспорт - Данная процедура доступна из других программных модулей.

Описание процедуры:

Процедура <Имя_процедуры>([[Знач] <Парам1> [=<ДефЗнач>], ... ,[Знач] <ПарамN> [=<ДефЗнач>]])[Экспорт] 
// Операторы;
[Возврат;]
КонецПроцедуры

Параметры:

Возврат - Завершает выполнение процедуры и осуществляет возврат. Не обязательно.

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

Описание функции:

Функция <Имя_функции>([[Знач] <Парам1> [=<ДефЗнач>], ... ,[Знач] <ПарамN> [=<ДефЗнач>]])[Экспорт] 
// Операторы ;
Возврат <Возвращаемое значение>;
КонецФункции

Возврат <Возвращаемое значение> Завершает выполнение функции и возвращает значение.
Возврат; Завершает выполнение процедуры.

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

Функции отличаются от процедур только тем, что возвращают <Возвращаемое значение>. Конец программной секции функции определяется по ключевому слову КонецФункции.

Вызов функции можно записывать как вызов процедуры, т.е. допускается не принимать от функции возвращаемое значение.

Исключения, внешний код

Попытка
    ПроверяемыйПараметр = Неопределено;
    Если ПроверяемыйПараметр Тогда
        //код, который не будет выполнен
    КонецЕсли;
Исключение
    Сообщить(ОписаниеОшибки());
КонецПопытки;

Генерация исключения

ВызватьИсключение [<Выражение>]; //описание - результат вычисления Выряжение.

Выполнить("") выполнить фрагмент кода, который передается ему в качестве строкового значения. Использовать аккуратно.

Управление отображением и событиями платформы

Модули конфигурации

Модуль сеанса Выполняется при старте системы «1С:Предприятие» в момент загрузки конфигурации. Предназначен для инициализации параметров сеанса и отработки действий, связанных с сеансом работы. Исполняется в привилегированном режиме. Установка параметров сеанса выполняется в обработчике события УстановкаПараметровСеанса(). Исполнение модуля сеанса происходит до начала исполнения модуля управляемого приложения и модуля внешнего соединения. Может содержать только определения процедур и функций, может использовать процедуры из общих модулей конфигурации и не
содержит экспортируемых процедур и функций.

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

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

Модуль присутствует только в сессии внешнего соединения, нет пользовательского интерфейса.

События платформы

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

События формы

Для настройки обработки событий формы необходимо сначала создать форму вместо формы по умолчанию. ПКМ на любом добавленном элементе формы -> События выведет список доступных обработчиков событий. Или в свойствах этого элемента.

1c_forms_actions.jpg

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

&НаКлиенте
Процедура ПересчитатьИтоговуюСумму() 
	ТабЧасть = Объект.ПереченьТоваров;
	ФиналСумма = 0; 	
	Для каждого Товар из ТабЧасть Цикл
		ФиналСумма = ФиналСумма + Товар.Сумма;
	КонецЦикла;
    Объект.СуммаПоДокументу = ФиналСумма;
КонецПроцедуры

&НаКлиенте
Процедура ПереченьТоваровКоличествоПриИзменении(Элемент)
	СтрТабЧасти = Элементы.ПереченьТоваров.ТекущиеДанные;
	СтрТабЧасти.Сумма = СтрТабЧасти.Цена * СтрТабЧасти.Количество;
	ПересчитатьИтоговуюСумму();
КонецПроцедуры

&НаКлиенте
Процедура ПереченьТоваровЦенаПриИзменении(Элемент)
	СтрТабЧасти = Элементы.ПереченьТоваров.ТекущиеДанные;
	СтрТабЧасти.Сумма = СтрТабЧасти.Цена * СтрТабЧасти.Количество;
	ПересчитатьИтоговуюСумму();
КонецПроцедуры

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

Программное создание обработчика события. 

ДобавитьОбработчик  <Событие>, <ОбработчикСобытия>;
Добавляет обработчик события. При добавлении обработчика события производится проверка соответствия числа параметров события числу параметров метода, назначаемого в качестве обработчика.

УдалитьОбработчик <Событие>, <ОбработчикСобытия>;
Удаляет обработчик события. При удалении обработчика события производится проверка соответствия числа параметров события числу параметров метода, назначенного в качестве обработчика.

 

Механизм блокировок

Хорошая статья по блокировкам на ИТС, но слегка устаревшая, в 8.3.14 алгоритм пессимистичной блокировки изменен.

Очень интересная статья, исследование блокировок.

Ускорение работы при высокой нагрузке, для погружения.

В простых словах и с примерами описание управляемой блокировки

Механизмы и типы блокировок.


Критичная тема для понимания работы платформы.


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

Механизм транзакционной блокировки - механизм обеспечения целостности и непротиворечивости данных средствами ядра СУБД на уровне транзакций. 

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

Блокировка на уровне объекта подразумевает наличие в БД третьей таблицы, в которой указывается, что Пользователь1 редактирует объект1. При попытке Пользователем2 изменить объект1, в операции будет отказано и до уровня старта изменений в данных дело не дойдет. Но здесь на первый план выходит алгоритм добавления и удаления данных из третьей таблицы.

Блокировка на уровне транзакции подразумевает отсутствие третьей таблицы, и при изменении данных в соответствии с логикой СУБД (либо запись об объекте1 в таблице1 и соответствующих записей в таблице2, либо целиком обоих таблиц), после успешного завершения блокировки снимаются. 

&НаСервереБезКонтекста
...
Попытка
	тестобъект.Заблокировать();
	// что-то делаем с объектом
    тестобъект.Разблокировать();
Исключение
	Сообщить("Не удалось заблокировать тест"); 
КонецПопытки;

 

Длительность блокировок

Детали установки блокировок

Настройка объектов конфигурации

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

Шаблоны кода

Получить версию объекта на клиенте и на сервере. 

&НаСервереБезКонтекста
Процедура ПолучитьВерсиюОбъектаНаСервере(ТекОбъект)
	Сообщить(ТекОбъект.ВерсияДанных);
КонецПроцедуры

&НаКлиенте
Процедура ПолучитьВерсиюОбъекта(Команда)
	ПолучитьВерсиюОбъектаНаСервере(Объект.Ссылка);
	Сообщить(Объект.ВерсияДанных);
КонецПроцедуры

Проверка необходимости обновления. 

&НаСервереБезКонтекста
Функция ВернутьВерсиюДанныхНаСервере(ТекОбъект)
	 Возврат ТекОбъект.ВерсияДанных;
КонецФункции

&НаКлиенте
Процедура ОболочкаОбработчика() 
	ВерсияНаСервере = ВернутьВерсиюДанныхНаСервере(Объект.Ссылка);
	Если ВерсияНаСервере <> Объект.ВерсияДанных Тогда
		ЭтаФорма.Прочитать();
        ПроверкаЭлементовНаВидимость();
	КонецЕсли;
КонецПроцедуры 

Проверить, заблокирован ли объект 

// Попытка установки блокировки
Объект = Номенклатура.ПолучитьОбъект();
Попытка
	Объект.Заблокировать();
Исключение
	// Данные объекта уже заблокированы.	
КонецПопытки;   


Проверка предположений.

Проверка факта запрета блокировки другим объектом.

&НаСервереБезКонтекста
Процедура ПроверкаПериодаБлокировкиНаСервере()
	тест = Справочники.ДляТранзакций.НайтиПоНаименованию("первый");  
	тест2 = Справочники.ДляТранзакций.НайтиПоНаименованию("первый");
	тестобъект = тест.ПолучитьОбъект();
	тестобъект2 = тест2.ПолучитьОбъект();
	Попытка
		тестобъект.Заблокировать();
		Сообщить("Объект тест заблокирован");
	Исключение
		Сообщить("Не удалось заблокировать тест"); 
	КонецПопытки;
	Попытка
		тестобъект2.Заблокировать();
		Сообщить("Объект тест2 заблокирован");
	Исключение
		Сообщить("Не удалось заблокировать тест2"); 
	КонецПопытки;
КонецПроцедуры

Объект тест2 заблокировать не удалось.

Блокировка держится до конца транзакции 

Механизм транзакций

Статья на ИТС

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

Свойства транзакции:

Особенности транзакции:

Из особенностей следуют правила:

Проверка понимания.

Определение и граница использования транзакции. Транзакции - нечто неделимое, возвращающее все в предыдущее состояние. Это осталось в голове после заумных текстов без тестов лапками. Первым, что пришло в голову - восстановить значение реквизита :) Обработка с полем ввода ТестовоеЧисло, 0 по умолчанию.

&НаСервере
Процедура БезОбработкиОшибокНаСервере()
	НачатьТранзакцию();
	ТестовоеЧисло = 5;
	ВызватьИсключение "Число не то!";
	ЗафиксироватьТранзакцию();
КонецПроцедуры

&НаКлиенте
Процедура БезОбработкиОшибок(Команда)
	БезОбработкиОшибокНаСервере();
КонецПроцедуры

Не удалось! Ошибка сгенерировалась, но ТестовоеЧисло стало 5. Ведь транзакции актуальны при изменении данных в базе, т е SQL запрос обрамляется чем-то типа "BEGIN ... COMMIT". Мой косяк, поехали дальше.

Ошибка при создании элемента справочника. Справочник Города. 

&НаСервереБезКонтекста
Процедура НовыйЭлементСправочникаНаСервере()
	НачатьТранзакцию();
	НовыйГород = Справочники.Города.СоздатьЭлемент();
	НовыйГород.Наименование = "Тестовый город";
	НовыйГород.Записать();
    НовыйГород2 = Справочники.Города.СоздатьЭлемент();
	НовыйГород2.Наименование = "Тестовый город 2";
	НовыйГород2.Записать();
	ВызватьИсключение "Город не правильный!";
	ЗафиксироватьТранзакцию();
КонецПроцедуры

Да, тестовые города не создались. Получилось! 

Вложенные транзакции (или то чего нет). 

&НаСервереБезКонтекста
Процедура ВложеннаяТранзакция()
	НачатьТранзакцию();
	Попытка
		НовыйГород = Справочники.Города.СоздатьЭлемент();
		НовыйГород.Наименование = "Тестовый город вложенный";
		НовыйГород.Записать(); 
		ВызватьИсключение "Город не правильный!";
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
	КонецПопытки;
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВложенныеТарнзакцииНаСервере()
	НачатьТранзакцию();
	НовыйГород = Справочники.Города.СоздатьЭлемент();
	НовыйГород.Наименование = "Тестовый город внешний";
	НовыйГород.Записать(); 
	ВложеннаяТранзакция();
	ЗафиксироватьТранзакцию();   
КонецПроцедуры

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

&НаСервереБезКонтекста
Процедура ВложеннаяТранзакция()
	НачатьТранзакцию();
	Попытка
		НовыйГород = Справочники.Города.СоздатьЭлемент();
		НовыйГород.Наименование = "Тестовый город вложенный";
		НовыйГород.Записать(); 
		ВызватьИсключение "Город не правильный!";
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
	КонецПопытки;
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВложенныеТарнзакцииНаСервере()
	НачатьТранзакцию();
	Попытка
		НовыйГород = Справочники.Города.СоздатьЭлемент();
		НовыйГород.Наименование = "Тестовый город внешний";
		НовыйГород.Записать(); 
		ВложеннаяТранзакция();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		Сообщить("Исключение было поймано");
	КонецПопытки;
КонецПроцедуры

Вполне логично, что сообщение не было сформировано.

Проверка функции ТранзакцияАктивна. 

&НаСервереБезКонтекста
Процедура НовыйЭлементСправочникаНаСервере() 
	Сообщить(ТранзакцияАктивна());
	НачатьТранзакцию();
	НовыйГород = Справочники.Города.СоздатьЭлемент();
	НовыйГород.Наименование = "Тестовый город 3";
	НовыйГород.Записать(); 
	Сообщить(ТранзакцияАктивна());
	ЗафиксироватьТранзакцию();    
	Сообщить(ТранзакцияАктивна());
КонецПроцедуры

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

&НаСервереБезКонтекста
Процедура ТранзакцияПриЧтенииНаСервере()
	МойГород = Справочники.Города.НайтиПоНаименованию("Иркутск");
	Сообщить(ТранзакцияАктивна());
	НовыйГород = Справочники.Города.СоздатьЭлемент();
	НовыйГород.Наименование = "Тестовый город 3";
	НовыйГород.Записать();
	Сообщить(ТранзакцияАктивна());
КонецПроцедуры

&НаКлиенте
Процедура ТранзакцияПриЧтении(Команда)
	ТранзакцияПриЧтенииНаСервере();
КонецПроцедуры

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

&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	Отказ = ТранзакцияАктивна(); 
КонецПроцедуры

И да, создать объект не удалось, значит транзакция была активна!

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

&НаСервереБезКонтекста
Процедура ВложеннаяТранзакция()
	НачатьТранзакцию();
	Попытка
		НовыйЭлемент = Справочники.ДляТранзакций.СоздатьЭлемент();
		НовыйЭлемент.Наименование = "Тестовый элемент внутренний";
		НовыйЭлемент.Записать();
		ВызватьИсключение "Ошибка!";
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		Сообщить("Ошибка во вложенной транзакции");
	КонецПопытки;
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ТестТранзакцииНаСервере()
	НачатьТранзакцию();
	Попытка
		Для сч = 1 По 5 Цикл
			НовыйЭлемент = Справочники.ДляТранзакций.СоздатьЭлемент();
			НовыйЭлемент.Наименование = "Тестовый элемент внешний " + Строка(сч);
			НовыйЭлемент.Записать(); 
			Сообщить("Попытка записи " + Строка(сч) + " внешнего элемента.");     
			//Если сч = 3 Тогда
			//	ВложеннаяТранзакция(); //ошибка в середине
			//КонецЕсли;
		КонецЦикла;  
		ВложеннаяТранзакция();//ошибка в конце
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		Сообщить("Исключение было поймано");
	КонецПопытки;
КонецПроцедуры

Сначала все логично. В указанном варианте (он повторяет предыдущий эксперимент) выведено 5 сообщений и "Ошибка во вложенной транзакции". Сообщение "Исключение было поймано" не отображается. 

А дальше ждал сюрприз. Если раскомментировать условие (ошибка на третьем шаге) то получается какая-то бабуйня: выведено 3 сообщения, сообщение "Ошибка во вложенной транзакции" и сообщение "Исключение было поймано"! То есть исключение транслируется наверх, если происходит между выполняемыми действиями. Однако если после выполняемых действий, но до фиксации транзакции - ошибка не транслируется наверх, а транзакция тихо откатывается.