В процессе разработки интерактивных обработок и мастеров заполнения данных часто возникает задача: последовательно создать несколько взаимосвязанных документов, запрашивая у пользователя уточняющие данные на разных шагах. При этом ключевым требованием является атомарность — если на каком-либо шаге пользователь отказывается от продолжения или возникает ошибка, все ранее сформированные документы должны быть отменены.
Разберем, почему попытка управлять транзакцией СУБД с клиента является принципиальной архитектурной ошибкой, и рассмотрим правильные варианты реализации такой логики в 1С:Предприятии.
Проанализируем базовые правила работы транзакционного механизма платформы 1С:
НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию() доступны исключительно на стороне сервера. На тонком клиенте базы данных как таковой нет, и управлять транзакцией напрямую невозможно.Таким образом, логика «начать транзакцию -> спросить пользователя -> продолжить транзакцию» не реализуема технически и недопустима архитектурно. Рассмотрим правильные подходы к решению этой задачи.
Вместо того чтобы сразу создавать и записывать документы в базу на каждом шаге, мы разделяем процесс на два независимых этапа: сбор/подготовка данных и финальная запись.
Разберем по шагам, как устроен этот механизм:
ПоместитьВоВременноеХранилище().Посмотрим на пример реализации финальной серверной процедуры записи:
&НаСервере
Процедура ЗаписатьПакетДокументовНаСервере(АдресДанныхВХранилище)
ДанныеДляЗаписи = ПолучитьИзВременногоХранилища(АдресДанныхВХранилище);
УдалитьИзВременногоХранилища(АдресДанныхВХранилище);
НачатьТранзакцию();
Попытка
Для Каждого ОписаниеДокумента Из ДанныеДляЗаписи Цикл
ДокументОбъект = Документы[ОписаниеДокумента.ИмяМетаданных].СоздатьДокумент();
ЗаполнитьЗначенияСвойств(ДокументОбъект, ОписаниеДокумента.Реквизиты);
Для Каждого СтрокаТЧ Из ОписаниеДокумента.ТабличнаяЧасть Цикл
НоваяСтрока = ДокументОбъект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЧ);
КонецЦикла;
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("СозданиеПакетаДокументов", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Ошибка при создании документов: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
КонецПроцедуры
Такой подход полностью исключает зависание блокировок в базе данных и гарантирует целостность: документы либо будут созданы и проведены все вместе, либо не будет создан ни один.
Если бизнес-логика требует проверки возможности проведения документа (например, проверки остатков по сложным алгоритмам модуля объекта) прямо в процессе диалога с пользователем, можно применить тестовую транзакцию с гарантированным откатом:
НачатьТранзакцию().РежимЗаписиДокумента.Проведение).ОтменитьТранзакцию(), чтобы изменения ни при каких условиях не зафиксировались в базе данных.В сценариях, когда физические ссылки на документы обязательно нужны уже на промежуточных шагах (например, для формирования связанных печатных форм или внешних интеграций), применяют механизм черновиков:
РежимЗаписиДокумента.Запись (без проведения) со специальным статусом или признаком черновика.УстановитьПометкуУдаления(Истина) или удаляет их непосредственно методом Удалить().НачатьТранзакцию() все черновики переводятся в рабочий статус и проводятся.Таким образом, правильная организация архитектуры интерактивного создания документов всегда опирается на вынос ожидания действий пользователя за пределы транзакций базы данных.