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