Каждый начинающий разработчик в среде «1С:Предприятие» рано или поздно сталкивается с обескураживающей ситуацией. Вы создали новый документ, заполнили его тестовыми данными в режиме пользователя (некоторые документы даже провели), затем открыли конфигуратор или внешнюю обработку и написали простейший запрос для получения ссылок. Код выглядит абсолютно корректно, синтаксических ошибок нет, но при выполнении запроса выборка оказывается пустой. Программа не выдает ошибок, но и данных не возвращает — «хоть ты тресни».
В этой статье мы подробно проанализируем, почему возникает подобное поведение платформы, разберем типичные ошибки при создании, копировании и переименовании объектов метаданных, а также рассмотрим технические нюансы работы СУБД и механизмы кэширования 1С, которые могут приводить к потере связи между кодом и реальными данными.
Обратимся к примеру, который часто встречается на практике и обсуждается на форумах разработчиков. Создан нетиповой документ. В базе данных есть физические записи — как проведенные, так и непроведенные. Написан следующий код:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заявка.Ссылка КАК Ссылка
|ИЗ
| Документ.Заявка КАК Заявка";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка результатов запроса
КонецЦикла;
Казалось бы, в кодовой конструкции невозможно ошибиться. Тем не менее, выборка пуста. При детальном анализе ситуации выясняется следующая картина: в конфигурации велась работа с двумя схожими документами (например, старая версия механизма заявок и новая разрабатываемая модель). В процессе разработки один из документов был переименован. В результате запрос отправлялся к пустой таблице нового документа, в то время как пользовательские данные фактически находились в таблице старого документа.
Рассмотрим подробнее неочевидные механизмы платформы 1С, которые приводят к подобным недоразумениям, и разберем способы их устранения.
Это самая распространенная методическая ошибка при создании новых объектов в конфигураторе 1С. Платформа строго разделяет понятия идентификаторов объектов:
Документ.ЗаявкаПокупателя).Рассмотрим наглядный пример. Разработчик решает создать новый документ на основе существующего путем копирования (через Ctrl+C / Ctrl+V или контекстное меню). Платформа создает копию и автоматически присваивает ей имя с числовым индексом, например, Заявка1. Синоним при этом копируется без изменений.
Если разработчик меняет синоним у обоих документов на одинаковое значение «Заявка», то в режиме «1С:Предприятие» в меню функций, списках документов и журналах пользователь будет видеть два абсолютно одинаковых пункта с названием «Заявка». Пользователь открывает один из списков, вводит туда данные, проводит документы. Однако физически эти документы записываются в таблицу объекта Документ.Заявка1. Программист же в кодовой базе пишет запрос к Документ.Заявка, обращаясь к совершенно другой (пустой) таблице метаданных.
Когда мы переименовываем имя самого объекта метаданных в конфигураторе (например, переименовываем старый рабочий документ Документ.Заявка в Документ.ЗаявкаСтарая, а новый, еще пустой документ называем Документ.Заявка), платформа 1С при обновлении конфигурации базы данных выполняет сложную процедуру реструктуризации.
На уровне системы управления базами данных (MS SQL Server, PostgreSQL и др.) происходят следующие процессы:
_Document150 на _Document150_Old).Документ.Заявка.В результате все ранее накопленные в базе документы остаются привязанными к старому объекту (который теперь называется ЗаявкаСтарая), а ваш новый запрос к Документ.Заявка обращается к только что созданной пустой таблице БД. Чтобы быстро проверить, к какой именно физической таблице обращается система, мы можем использовать встроенную функцию получения структуры хранения базы данных.
Выполним следующий проверочный код в отладочном режиме:
СтруктураХранения = ПолучитьСтруктуруХраненияБазыДанных("Документ.Заявка");
Для Каждого СтрокаТаблицы Из СтруктураХранения Цикл
Сообщить("Метаданные: " + СтрокаТаблицы.ИмяМетаданных);
Сообщить("Имя таблицы в СУБД: " + СтрокаТаблицы.ИмяТаблицыХранения);
КонецЦикла;
Проанализировав вывод данного фрагмента, мы сможем четко сопоставить имена метаданных в конфигураторе с реальными таблицами в базе данных SQL.
Даже если вы исправили все имена в конфигураторе, проверили синонимы и убедились в правильности структуры, запрос все равно может возвращать пустой результат. Причиной тому часто выступает механизм динамического обновления («демоническое обновление»), выполняемое без монопольного отключения пользователей.
При динамическом обновлении сервер 1С:Предприятия и локальные рабочие станции пользователей используют кэшированные версии метаданных. В результате возникает рассинхронизация:
Документ.Заявка понимается старая структура метаданных.Для решения этой проблемы необходимо выполнить жесткую очистку кэша метаданных. Разберем по шагам, как это сделать:
F7).%AppData%\1C\1Cv8\%LocalAppData%\1C\1Cv8\Еще одна неочевидная причина, почему простейший запрос по существующим в интерфейсе документам возвращает пустой результат — это влияние механизмов разграничения прав доступа на уровне записей (Row-Level Security, или RLS). Если вы тестируете выполнение запроса под учетной записью пользователя с ограниченными правами доступа (например, «Менеджер по продажам» или «Бухгалтер»), система безопасности 1С неявно модифицирует текст вашего запроса.
При выполнении запроса платформа автоматически добавляет скрытые условия связи с таблицами ограничений (например, по разрешенным организациям, подразделениям или контрагентам). Если для данного пользователя не настроены соответствующие политики доступа, запрос вернет пустой результат, несмотря на то, что физически документы существуют в базе.
Чтобы проверить эту гипотезу, нам необходимо выполнить запрос в привилегированном режиме, который полностью отключает проверку прав RLS на уровне платформы. Рассмотрим пример кода:
// Включаем привилегированный режим для обхода RLS
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заявка.Ссылка КАК Ссылка
|ИЗ
| Документ.Заявка КАК Заявка";
Выборка = Запрос.Выполнить().Выбрать();
Сообщить("Количество найденных документов: " + Выборка.Количество());
// Возвращаем стандартный режим проверки прав
УстановитьПривилегированныйРежим(Ложь);
Если в привилегированном режиме документы успешно выбираются, значит, проблема кроется исключительно в настройках ролей и ограничений доступа для текущего пользователя информационной базы.
Если вы столкнулись с ситуацией, когда простейший запрос по новому документу не возвращает данные, рекомендуем действовать по следующему пошаговому алгоритму:
ИЗ (например, Документ.ИмяВашегоДокумента). Не ориентируйтесь на синоним документа, который отображается в режиме предприятия.Соблюдение этих простых правил и понимание внутренней структуры хранения данных 1С позволит вам быстро локализовать проблему и избежать досадных ошибок на этапе проектирования и доработки нетиповых конфигураций.