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