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