Среди разработчиков на платформе 1С:Предприятие периодически возникают слухи о кардинальных изменениях в работе механизмов платформы. Один из таких обсуждаемых вопросов — якобы планируемый фирмой «1С» отказ от поддержки оператора ОБЪЕДИНИТЬ (или ОБЪЕДИНИТЬ ВСЕ) в запросах динамических списков. Давайте проанализируем эту ситуацию, выясним реальное положение дел и разберем технические нюансы работы динамических списков.
Сразу ответим на главный вопрос: **нет, это неправда**. Фирма «1С» не планирует и никогда не анонсировала отключение оператора ОБЪЕДИНИТЬ в запросах динамических списков. Вероятность такого шага стремится к нулю, поскольку это нарушило бы обратную совместимость со множеством существующих решений и типовых конфигураций.
Однако откуда же берутся подобные слухи? Чаще всего они возникают из-за неверного истолкования технических ограничений платформы, стандартов разработки фирм «1С» и поведения среды разработки (например, 1C:EDT или Конфигуратора). Рассмотрим подробнее, как именно устроен динамический список и почему использование объединений в нем требует особого внимания.
Разберем механизм работы объекта ДинамическийСписок. В его основе лежит система компоновки данных (СКД). Главная задача динамического списка — обеспечивать быстрое, порционное (постраничное) считывание данных из базы по мере того, как пользователь прокручивает таблицу на форме.
Для реализации этого механизма платформе критически важно понимать, как однозначно идентифицировать каждую строчку в порции данных. Здесь ключевую роль играет свойство Основная таблица (ОсновнаяТаблица):
Ссылка или КлючЗаписи). По этому ключу рассчитываются права доступа (RLS), определяется доступность стандартных команд (создание, пометка на удаление, открытие формы элемента), а также строятся эффективные запросы для выборки порций данных.Выясним, какие именно сложности возникают, когда мы пытаемся написать запрос с объединением нескольких таблиц в динамическом списке.
Если у динамического списка указана ОсновнаяТаблица, а ваш запрос с оператором ОБЪЕДИНИТЬ в результате выборки возвращает две одинаковые ссылки (повторяющиеся ключи), платформа при построении и считывании страницы данных вызовет критическое исключение (ошибку дублирования ключей).
В современных инструментах разработки, таких как 1C:EDT, встроен жесткий валидатор конфигурации. Если в корневом запросе динамического списка при установленной основной таблице используется конструктор объединения, среда разработки может выдавать предупреждение или ошибку валидации. Это связано с тем, что платформенный генератор запросов СКД не всегда может корректно наложить условия порционного считывания и RLS на корневое объединение.
Если разработчик решает объединить данные из совершенно разных таблиц (например, справочника Контрагенты и справочника ФизическиеЛица), он не может указать одну ОсновнуюТаблицу. Без основной таблицы динамический список вынужден вычитывать данные большими объемами, что на объектах с сотнями тысяч записей приводит к существенным задержкам интерфейса.
Проанализируем рекомендации фирмы «1С», опубликованные на ресурсах ИТС (в частности, Стандарт разработки #std732). Фирма «1С» действительно **не рекомендует** создавать тяжелые запросы с объединениями непосредственно в динамических списках, и вот почему:
ОБЪЕДИНИТЬ заставляет СУБД выполнять дополнительную и крайне затратную операцию поиска и удаления дублей (аналог DISTINCT). В динамических списках, где отклик интерфейса должен быть мгновенным, это недопустимо. Всегда следует использовать ОБЪЕДИНИТЬ ВСЕ.Рассмотрим практический способ решения проблемы, если объединить данные в динамическом списке всё же необходимо, но требуется сохранить указанную основную таблицу и избежать ошибок валидации.
Решением является обертывание объединения во **вложенный запрос** с явным выбором уникального ключевого поля во внешнем запросе.
Посмотрим на пример правильного построения запроса динамического списка:
ВЫБРАТЬ
ВложенныйЗапрос.Ссылка КАК Ссылка,
ВложенныйЗапрос.Дата КАК Дата,
ВложенныйЗапрос.Номер КАК Номер,
ВложенныйЗапрос.СуммаДокумента КАК СуммаДокумента
ИЗ
(ВЫБРАТЬ
ЗаказПокупателя.Ссылка КАК Ссылка,
ЗаказПокупателя.Дата КАК Дата,
ЗаказПокупателя.Номер КАК Номер,
ЗаказПокупателя.СуммаДокумента КАК СуммаДокумента
ИЗ
Документ.ЗаказПокупателя КАК ЗаказПокупателя
ГДЕ
ЗаказПокупателя.Проведен = ИСТИНА
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СчетНаОплату.Ссылка КАК Ссылка,
СчетНаОплату.Дата КАК Дата,
СчетНаОплату.Номер КАК Номер,
СчетНаОплату.СуммаДокумента КАК СуммаДокумента
ИЗ
Документ.СчетНаОплатуПокупателю КАК СчетНаОплату
ГДЕ
СчетНаОплату.Проведен = ИСТИНА) КАК ВложенныйЗапрос
При таком подходе внешняя выборка обращается ко вложенному запросу, а платформа может безопасно накладывать ограничения и связи. Однако помните: если у вас задана основная таблица (например, Документ.ЗаказПокупателя), попадание в результат ссылки другого типа (например, СчетНаОплатуПокупателю) может привести к некорректной работе стандартных команд формы.
Если задача требует вывода сложных скомпонованных данных из множества источников, и при этом:
В этих случаях действительно целесообразно отказаться от ДинамическогоСписка и сформировать обычную ТаблицуЗначений на сервере с последующим выводом на форму. Но делать это нужно исходя из требований производительности и архитектуры, а не из-за несуществующих запретов платформы.
Подведем итоги нашего анализа:
ОБЪЕДИНИТЬ в динамических списках — это миф. Разработчики 1С не отключают этот функционал.ОБЪЕДИНИТЬ ВСЕ и при необходимости оборачивать объединение во вложенный запрос.