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