При разработке обработок для заполнения регистров сведений программисты часто сталкиваются с логическими ошибками, которые приводят к появлению лишних или дублирующихся записей. Особенно остро эта проблема встает при использовании нескольких вложенных циклов. В данной статье мы разберем, почему возникает так называемая «задвойка» (или даже «зачетверка»), как оптимизировать алгоритм заполнения и как правильно работать со строками для формирования сложных идентификаторов.
Рассмотрим ситуацию, когда нам необходимо перебрать несколько коллекций данных (массивы видов ремонта, моделей, двигателей и КПП) и для каждой комбинации создать запись в регистре. Проанализируем фрагмент кода, в котором используется пять вложенных циклов:
Для каждого стр1 из Массив2 Цикл // Виды ремонта
Для Каждого стр5 из Массив5 цикл // Модели
Для каждого стр3 из Материалы цикл // Номенклатура
Для каждого стр2 Из Массив3 Цикл // Типы двигателя
Для каждого стр4 из Массив4 цикл // Типы КПП
рег = РегистрыСведений.СервисМеню.СоздатьМенеджерЗаписи();
// ... заполнение полей ...
рег.Записать();
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Когда мы вкладываем циклы друг в друга, количество итераций самого глубокого цикла вычисляется как произведение длин всех массивов. Это называется декартовым произведением. Если в каждом массиве будет хотя бы по 5 элементов, количество записей составит 5 * 5 * 5 * 5 * 5 = 3125. Если автор видит «четыре копии», это означает, что один из массивов содержит 4 элемента, которые перемножаются с остальными данными, создавая избыточность в тех измерениях, где она не предполагалась.
Выясним причину: часто программист ошибочно помещает перебор материалов (номенклатуры) внутрь перебора технических характеристик (двигатель, КПП), хотя логика задачи может подразумевать, что конкретный материал привязан только к определенной модели или виду ремонта. Чтобы исправить это, необходимо пересмотреть структуру вложенности или использовать запросы для предварительной подготовки данных.
Обратим внимание на важный архитектурный момент: использование СоздатьМенеджерЗаписи() внутри вложенных циклов является крайне непроизводительным. Рассмотрим, как это работает на уровне базы данных: на каждой итерации система создает отдельный объект, открывает транзакцию, записывает одну строку и закрывает транзакцию.
Вместо этого рекомендуется использовать объект НаборЗаписей. Проанализируем правильный алгоритм:
РегистрыСведений.НазваниеРегистра.СоздатьНаборЗаписей().Набор.Загрузить(ТаблицаДанных).Набор.Записать().Такой подход сокращает время работы обработки в десятки раз и минимизирует риск блокировок базы данных.
Часто при заполнении регистров требуется сформировать уникальный «Код модели» или описание на основе нескольких параметров. Рассмотрим задачу: из строки 37CX920072015 нужно получить только первые три символа (37C), из года 2007 — последние две цифры (07) и соединить их через подчеркивание.
Для решения этой задачи в 1С применяются функции Лев() (взять символы слева), Прав() (взять символы справа) и Сред() (взять из середины). Разберем пример кода, предложенный в обсуждении:
Рег.КодМодели = стр5.НаименованиеТОЙОТА + "_" + Лев(стр2, 3) + "_" + Прав(стр4, 2) + "_" + Прав(НачПериода, 2) + "/" + Прав(КонПериода, 2);
Важные правила конкатенации (сложения) строк:
"" + Число + "Текст".Формат(). Например, чтобы получить две последние цифры года из даты, используйте Формат(НачПериода, "ДФ=гг").Начиная с версии платформы 8.3.6, для склейки сложных строк рекомендуется использовать функцию СтрШаблон(). Это делает код более читаемым и защищает от ошибок типизации. Рассмотрим, как мог бы выглядеть код автора при использовании шаблонов:
ШаблонКода = "%1_%2_%3_%4/%5";
Рег.КодМодели = СтрШаблон(ШаблонКода,
стр5.НаименованиеТОЙОТА,
Лев(стр2, 3),
Прав(стр4, 2),
Прав(Строка(Год(НачПериода)), 2),
Прав(Строка(Год(КонПериода)), 2)
);
Этот подход позволяет четко видеть структуру формируемой строки и легко вносить изменения в формат разделителей (нижнее подчеркивание, косая черта и т.д.).
Для предотвращения «задвоений» в циклах и повышения качества кода придерживайтесь следующих правил:
Для каждого.МенеджерЗаписи.Лев(), Прав() и Формат(), а также не забывайте о явном преобразовании типов при сложении строк с числами или датами.