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