При разработке обработок по переносу или заполнению данных в 1С начинающие программисты часто совершают фундаментальную ошибку: они пытаются перенести логику интерактивной работы пользователя на программные алгоритмы. Яркий пример — создание новых элементов справочника путем открытия, заполнения и закрытия формы нового элемента в цикле. Давайте разберем, почему такой подход называют «лютейшей дичью», какие скрытые опасности он в себе таит и как решить эту задачу профессионально, быстро и безопасно.
Рассмотрим исходную задачу. Автору требовалось обойти справочник Номенклатура, найти элементы, содержащие специальный символ-разделитель #, извлечь из наименования код и новое имя, а затем создать новые записи в справочнике КлассификаторУКТВЭД. При этом нужно было исключить дублирование кодов.
Первая попытка автора (из Сообщения 0) выглядела так: он получал форму нового элемента один раз вне цикла, а в самом цикле пытался перезаписывать значения ее полей, записывать и закрывать форму. Логично, что в результате в базе создавался лишь один элемент — последний из выборки. Это происходило потому, что объект формы был инициализирован единожды, и каждая итерация цикла просто затирала старые значения в полях формы новыми, выполняя в конце финальную запись последнего значения.
В Сообщении 5 автор нашел «решение», которое посчитал рабочим: перенес получение формы внутрь цикла:
Для Элемент = 1 По БезДублей.Количество() Цикл
Форма = Справочники.КлассификаторУКТВЭД.ПолучитьФормуНовогоЭлемента();
Форма.Открыть();
// Заполнение полей формы...
Форма.Записать();
Форма.Закрыть();
КонецЦикла;
Несмотря на то, что этот код формально «работает», он является крайне неоптимальным и опасным для стабильности системы. Проанализируем ситуацию и разберем, почему этот код категорически нельзя использовать в реальных конфигурациях.
ПолучитьФормуНовогоЭлемента() инициализирует визуальный интерфейс (UI). Когда мы выполняем этот метод в цикле сотни или тысячи раз, платформа тратит колоссальные ресурсы компьютера на создание, прорисовку, открытие и закрытие окон. Это приводит к дикому зависанию интерфейса, мерцанию экрана и падению производительности.БезДублей и БезДублейПробел, но совершенно забыл про массив тест1, где хранились очищенные наименования. В итоге при заполнении формы он написал:
Форма.ЭлементыФормы.Наименование.Значение = БезДублейПробел[Элемент - 1];
ПолучитьОбъект()). Для проверки наименования автор считывал весь объект целиком из базы данных. Это создает избыточную нагрузку на СУБД, так как вместо чтения одной текстовой строки платформа тянет из базы все реквизиты, табличные части и права доступа.В профессиональной разработке на платформе 1С:Предприятие для массового создания или изменения данных строго соблюдается разделение интерфейса и логики данных. Работа с объектами базы данных должна происходить исключительно на уровне программных объектов (без визуальных форм) и, желательно, на стороне сервера.
Рассмотрим правильный алгоритм решения задачи по шагам:
Выбрать() и проверять текстовые поля на клиенте. Вместо этого мы напишем эффективный запрос к СУБД, который сразу отберет только нужные элементы, содержащие символ #, и сразу отсечет дубликаты с помощью ключевого слова РАЗЛИЧНЫЕ.Соответствие для быстрого поиска в оперативной памяти.СоздатьЭлемент(). Этот метод создает объект в памяти, заполняет его реквизиты напрямую и записывает в базу одной командой Записать().Посмотрим на пример реализации этого алгоритма:
Процедура КнопкаВыполнитьНажатие(Кнопка)
// Шаг 1. Быстро выбираем уникальные наименования из Номенклатуры с помощью запроса
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура.Наименование КАК ПолноеНаименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО ""%#%""";
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Нет подходящих данных в Номенклатуре для переноса.");
Возврат;
КонецЕсли;
// Шаг 2. Загружаем уже существующие коды УКТВЭД в Соответствие для мгновенной проверки
СуществующиеКоды = Новый Соответствие;
ВыборкаКодов = Справочники.КлассификаторУКТВЭД.Выбрать();
Пока ВыборкаКодов.Следующий() Цикл
СуществующиеКоды.Вставить(ВыборкаКодов.Код, Истина);
КонецЦикла;
// Шаг 3. Обработка данных и программное создание элементов без участия форм
Выборка = РезультатЗапроса.Выбрать();
КоличествоДобавленных = 0;
Пока Выборка.Следующий() Цикл
СтрокаНоменклатуры = Выборка.ПолноеНаименование;
Разделитель = Найти(СтрокаНоменклатуры, "#");
// Выделяем код и очищенное наименование
СтрокаКода = СокрЛП(Лев(СтрокаНоменклатуры, Разделитель - 1));
СтрокаНаименования = СокрЛП(Сред(СтрокаНоменклатуры, Разделитель + 1));
// Форматируем код по маске (например, "XXXX XX XX XX" для классификатора УКТВЭД)
ФорматированныйКод = Лев(СтрокаКода, 4) + " " + Сред(СтрокаКода, 5, 2) + " " + Сред(СтрокаКода, 7, 2) + " " + Сред(СтрокаКода, 9, 2);
// Быстрая проверка на дубликат по кэшу в памяти
Если СуществующиеКоды[ФорматированныйКод] <> Неопределено Тогда
Продолжить; // Такой код уже существует в базе, пропускаем его
КонецЕсли;
// Создаем новый элемент справочника НАПРЯМУЮ в базе данных
НовыйЭлемент = Справочники.КлассификаторУКТВЭД.СоздатьЭлемент();
НовыйЭлемент.Код = ФорматированныйКод;
НовыйЭлемент.Наименование = СтрокаНаименования;
НовыйЭлемент.НаименованиеПолное = СтрокаНаименования;
Попытка
НовыйЭлемент.Записать();
// Сразу добавляем новый код в кэш, чтобы избежать дублей внутри этой же транзакции
СуществующиеКоды.Вставить(ФорматированныйКод, Истина);
КоличествоДобавленных = КоличествоДобавленных + 1;
Исключение
Сообщить("Не удалось записать код " + ФорматированныйКод + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Сообщить("Обработка успешно завершена. Создано элементов: " + КоличествоДобавленных);
КонецПроцедуры
Соответствие. Это чрезвычайно эффективный инструмент для поиска дубликатов. Поиск значения по ключу в Соответствие происходит практически мгновенно (сложность O(1)), в отличие от метода Найти() в массиве, который последовательно перебирает все элементы (сложность O(N)).НовыйЭлемент.Записать() в блок Попытка...Исключение. Если один из элементов не запишется (например, из-за нарушения уникальности или блокировок базы данных), программа не вылетит с ошибкой, а продолжит корректную обработку остальных строк, зафиксировав проблему в окне сообщений.Таким образом, мы избавились от «войны клонов» интерактивных форм, устранили потенциальные риски падения производительности системы и исправили логические ошибки с потерей данных, которые допустил автор темы. Помните: работа с данными в циклах всегда должна выполняться через объектную модель 1С на сервере, минуя элементы интерфейса!