При разработке функционала заполнения штрихкодов для номенклатуры в табличной части документа или обработки разработчики часто сталкиваются с логическими ошибками. Типичный сценарий: запрос выполняется ко всей таблице регистра сведений без условий, внутри цикла проверяется соответствие текущей активной строке, а вместо обновления данных создаются новые строки или код срабатывает только для одной позиции. Разберем типичные ошибки такого подхода и рассмотрим правильные варианты реализации задачи.
Проанализируем исходный фрагмент кода, вызывающий проблемы:
СТЧ = ЭлементыФормы.Товары.ТекущиеДанные;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Штрихкод,
| Штрихкоды.Владелец.Ссылка КАК Товар,
| Штрихкоды.ХарактеристикаНоменклатуры
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды";
Результат = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = Результат.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Если СТЧ.Номенклатура = ВыборкаДетальныеЗаписи.Товар Тогда
Если СТЧ.ХарактеристикаНоменклатуры = ВыборкаДетальныеЗаписи.ХарактеристикаНоменклатуры Тогда
НоваяСтрока = Товары.Добавить();
НоваяСтрока.Номенклатура = ВыборкаДетальныеЗаписи.Товар;
НоваяСтрока.ХарактеристикаНоменклатуры = ВыборкаДетальныеЗаписи.ХарактеристикаНоменклатуры;
НоваяСтрока.Штрихкода = ВыборкаДетальныеЗаписи.Штрихкод;
КонецЕсли;
КонецЕсли;
КонецЦикла;
В этом коде допущено сразу несколько грубых архитектурных и логических ошибок:
СТЧ получает значение ЭлементыФормы.Товары.ТекущиеДанные. Это ссылка только на одну активную строку, на которой установлен фокус пользователя. Цикл сравнивает записи всего регистра только с этой одной строкой, поэтому обработка всей таблицы не происходит. Кроме того, если фокус в таблице не установлен, ТекущиеДанные вернет Неопределено, что приведет к исключению «Поле объекта не обнаружено».Товары.Добавить() создает новую дублирующую строку при каждом найденном штрихкоде, вместо того чтобы записать штрихкод в существующую строку.ГДЕ заставляет СУБД считывать все записи регистра в память. При росте базы данных этот запрос вызовет резкое падение производительности.Штрихкоды.Владелец.Ссылка содержит лишнее обращение через точку к реквизиту Ссылка, так как поле Владелец само по себе уже содержит ссылку на справочник номенклатуры.Если задача заключается в заполнении штрихкода строго для текущей редактируемой строки, выполнять тяжелый запрос не требуется. В случае независимого непериодического регистра сведений проще всего воспользоваться методом Получить() менеджера регистра сведений.
Разберем по шагам правильный алгоритм:
СТЧ = ЭлементыФормы.Товары.ТекущиеДанные;
// Проверяем, что строка действительно выбрана
Если СТЧ <> Неопределено Тогда
Отбор = Новый Структура;
Отбор.Вставить("Владелец", СТЧ.Номенклатура);
Отбор.Вставить("ХарактеристикаНоменклатуры", СТЧ.ХарактеристикаНоменклатуры);
ДанныеЗаписи = РегистрыСведений.Штрихкоды.Получить(Отбор);
СТЧ.Штрихкод = ДанныеЗаписи.Штрихкод;
КонецЕсли;
Если же необходимо использовать запрос для текущей строки (например, когда требуется отобрать конкретный тип штрихкода или единицу измерения), передаем параметры непосредственно в условие запроса:
СТЧ = ЭлементыФормы.Товары.ТекущиеДанные;
Если СТЧ <> Неопределено Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Штрихкоды.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
|ГДЕ
| Штрихкоды.Владелец = &Номенклатура
| И Штрихкоды.ХарактеристикаНоменклатуры = &Характеристика";
Запрос.УстановитьПараметр("Номенклатура", СТЧ.Номенклатура);
Запрос.УстановитьПараметр("Характеристика", СТЧ.ХарактеристикаНоменклатуры);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
СТЧ.Штрихкод = Выборка.Штрихкод;
КонецЕсли;
КонецЕсли;
Если требуется заполнить штрихкоды сразу для всех строк табличной части документа, категорически не рекомендуется выполнять запрос в цикле. Оптимальный подход — передать данные табличной части во временную таблицу запроса и соединить ее с регистром сведений одним обращением к базе данных.
Рассмотрим реализацию массового заполнения:
// Создаем менеджер временных таблиц
МВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
// Передаем табличную часть в запрос
Запрос.Текст =
"ВЫБРАТЬ
| ТабЧасть.НомерСтроки КАК НомерСтроки,
| ТабЧасть.Номенклатура КАК Номенклатура,
| ТабЧасть.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТабличнаяЧасть КАК ТабЧасть;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Товары.НомерСтроки КАК НомерСтроки,
| ЕСТЬNULL(Штрихкоды.Штрихкод, """") КАК Штрихкод
|ИЗ
| ВТ_Товары КАК ВТ_Товары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Штрихкоды КАК Штрихкоды
| ПО ВТ_Товары.Номенклатура = Штрихкоды.Владелец
| И ВТ_Товары.ХарактеристикаНоменклатуры = Штрихкоды.ХарактеристикаНоменклатуры";
Запрос.УстановитьПараметр("ТабличнаяЧасть", Товары.Выгрузить());
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
// Заполняем штрихкоды в исходной табличной части по номеру строки
Пока Выборка.Следующий() Цикл
СтрокаТЧ = Товары[Выборка.НомерСтроки - 1];
СтрокаТЧ.Штрихкод = Выборка.Штрихкод;
КонецЦикла;
СправочникСсылка.ХарактеристикиНоменклатуры. Убедитесь, что отбор не передает значение Неопределено вместо пустой ссылки, иначе условие равенства не сработает.ВЫБРАТЬ ПЕРВЫЕ 1.