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