В практике разработки на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с ситуацией, когда при выполнении встроенного ("черного") запроса к справочнику или регистру значения атрибутов документов (таких как ДатаДок или НомерДок) возвращаются пустыми. Это происходит даже в тех случаях, когда сам реквизит, ссылающийся на документ, визуально заполнен. Проанализируем, почему так происходит, и рассмотрим все доступные способы решения этой задачи.
Разберем внутреннюю механику платформы. В 1С 7.7 реквизит типа Документ без указания конкретного вида называется реквизитом неопределенного типа. В базе данных такие значения хранятся в виде составного идентификатора: первые символы определяют вид документа, остальные — его уникальный номер (ID) в системе. Стандартный движок запросов 1С 7.7 не обладает механизмом автоматического разыменования (автоматического соединения таблиц) для таких полей. Когда мы пишем в запросе ДатаДок = Справочник.Партии.ПриходныйДокумент.ДатаДок, система не знает, к таблице какого именно документа (например, ПоступлениеТМЦ или ОприходованиеТМЦ) ей нужно обратиться, чтобы считать поле даты.
Самый простой и стандартный способ — это "подсказать" парсеру запросов все возможные виды документов, которые могут встретиться в этом реквизите. Рассмотрим, как должен выглядеть текст запроса в этом случае. Нам необходимо перечислить пути через запятую внутри одной переменной запроса.
ТекстЗапроса = "
|Номенклатура = Справочник.Партии.Владелец;
|ПриходныйДокумент = Справочник.Партии.ПриходныйДокумент;
|ДатаДок = Справочник.Партии.ПриходныйДокумент.ПоступлениеТМЦ.ДатаДок,
| Справочник.Партии.ПриходныйДокумент.ОприходованиеТМЦ.ДатаДок,
| Справочник.Партии.ПриходныйДокумент.ВозвратОтПокупателя.ДатаДок;
|Группировка Номенклатура;
|Группировка ПриходныйДокумент;
|";
Проанализируем этот код: 1С последовательно проверит каждый вид документа. Если в реквизите ПриходныйДокумент окажется ПоступлениеТМЦ, система возьмет его дату. Если список документов в конфигурации очень большой, этот метод становится трудоемким, но он является единственным штатным способом получить дату внутри самого тела запроса для последующей сортировки или фильтрации.
Если нам не нужно сортировать результаты запроса по дате или накладывать условия на дату непосредственно в тексте запроса, мы можем получить её гораздо проще. Выясним, как это сделать: достаточно просто выбрать сам документ в запросе, а дату получить при обработке результата.
Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Пока Запрос.Группировка(1) = 1 Цикл
Пока Запрос.Группировка(2) = 1 Цикл
// В переменной Док находится ссылка на документ
Док = Запрос.ПриходныйДокумент;
// Обращаемся к атрибуту объекта напрямую
ДатаДокумента = Док.ДатаДок;
Сообщить("Документ: " + Док + " от " + ДатаДокумента);
КонецЦикла;
КонецЦикла;
КонецЕсли;
Рассмотрим важный нюанс: при таком подходе 1С выполнит дополнительное обращение к базе данных для каждого документа в цикле. Если записей тысячи, отчет будет работать медленно. Однако для разовых задач по выгрузке данных этот метод наиболее предпочтителен из-за простоты реализации.
Чтобы не перечислять десятки видов документов вручную, мы можем автоматизировать процесс, используя объект Метаданные. Посмотрим на пример функции, которая сформирует нужную строку для запроса:
Функция СформироватьПутиКДате(ИмяСправочника, ИмяРеквизита)
Результат = "";
Для ии = 1 По Метаданные.Документ() Цикл
ИмяДока = Метаданные.Документ(ии).Идентификатор;
Результат = Результат + "Справочник." + ИмяСправочника + "." + ИмяРеквизита + "." + ИмяДока + ".ДатаДок,";
КонецЦикла;
// Удаляем последнюю запятую
Возврат Лев(Результат, СтрДлина(Результат)-1);
КонецФункции
Использование такой функции позволит динамически подставить в текст запроса все существующие в конфигурации типы документов, что полностью решает проблему "пустых дат" без ручного кодинга.
Проанализируем ситуацию с точки зрения архитектуры 1С. Если задача стоит в получении первых дат партий (как в примере автора темы), то обращение к справочнику Партии — не самый оптимальный путь. В типовых конфигурациях (например, "Торговля и Склад") информация о движениях партий хранится в регистрах (например, ПартииНаличие).
В запросах к регистрам существует служебное поле ТекущийДокумент. Оно всегда типизировано и позволяет получить дату без лишних ухищрений. Посмотрим на пример логики:
ТекущийДокумент.ДатаДок.Это решение будет работать значительно быстрее, так как оно опирается на индексы таблиц движений, а не на полный перебор справочника.
Если ваша база работает на MS SQL Server и вы используете внешние компоненты, такие как 1С++, проблему можно решить одним эффективным запросом. В таблицах SQL данные о датах всех документов хранятся в одной общей таблице _1SJOURN. Нам достаточно соединить (JOIN) таблицу справочника партий с таблицей журнала документов по полю IDDoc. Это позволит мгновенно получить даты для любого количества записей, игнорируя любые ограничения встроенного языка запросов 1С.
Важно помнить: При работе со справочником "Партии" всегда проверяйте, что документ в реквизите ПриходныйДокумент действительно существует (не был удален или помечен на удаление), так как в 1С 7.7 возможны "битые" ссылки, которые также приведут к пустой дате при любых способах обращения.