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