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