При работе со справочниками и документами в управляемых формах 1С (например, со справочником Номенклатура в конфигурации «1С:Управление торговлей») пользователи и разработчики могут столкнуться с аварийной ошибкой платформы: «Обнаружено дублирование ключевых значений в колонке Ссылка». Ошибка часто проявляется не сразу, а только при включении определенных отборов, поиске или установке фильтра по иерархии.
Разберем по шагам механизм возникновения этой ошибки, выясним способы ее диагностики и рассмотрим практические варианты устранения.
Для отображения списков объектов в управляемом интерфейсе используется элемент формы ДинамическийСписок. По умолчанию он работает в режиме порционной выборки данных из базы.
Для корректного позиционирования курсора, постраничной загрузки и навигации платформе требуется уникальный ключ строки. В качестве такого ключа обычно выступает поле Ссылка основной таблицы конфигурации. Если в результате выполнения запроса поле Ссылка повторяется хотя бы дважды, платформа 1С не может однозначно сопоставить строку интерфейса с записью таблицы базы данных и выбрасывает исключение.
Особенность заключается в том, что ДинамическийСписок функционирует на базе Системы компоновки данных (СКД). Исходный текст произвольного запроса не выполняется «как есть» — СКД на лету модифицирует его в зависимости от включенных пользователем колонок, отборов и группировок. Поэтому в консоли запросов базовый текст может возвращать корректный результат, а в интерфейсе с примененным фильтром приводить к ошибке.
Проанализируем распространенные сценарии, приводящие к дублированию ключа:
СрезПоследних (или обращение к срезу без передачи точки времени).Чтобы понять, какое именно соединение размножает строки, необходимо получить реальный исполняемый текст запроса, который формирует СКД со всеми наложенными отборами.
Рассмотрим два основных способа перехвата запроса:
Мы можем программно сгенерировать исполняемый макет динамического списка в точке останова отладчика или во внешней обработке:
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
Компоновщик = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = Компоновщик.Выполнить(Схема, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// В свойстве Макет.НаборыДанных будет содержаться итоговый сгенерированный запрос
Если ошибка возникает в сложном контексте типовой конфигурации, настроим сбор событий DBMSSQL/DBPOSTGRS или EXCP в Технологическом журнале 1С. В журнале будет зафиксирован финальный SQL-запрос, отправленный к СУБД, в котором наглядно видны все присоединенные таблицы.
После получения текста запроса проверим его в консоли запросов на наличие дублей с помощью группировки:
ВЫБРАТЬ
Т.Ссылка КАК Ссылка,
КОЛИЧЕСТВО(Т.Ссылка) КАК КоличествоДублей
ИЗ
( ВЫБРАТЬ
СпрНоменклатура.Ссылка КАК Ссылка,
СпрНоменклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура ) КАК Т
СГРУППИРОВАТЬ ПО
Т.Ссылка
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Т.Ссылка) > 1
Разберем варианты исправления ошибки в зависимости от источника ее возникновения:
Если к списку необходимо присоединить данные из таблицы, где на один объект может приходиться несколько записей (например, дополнительные реквизиты, штрихкоды, цены), предварительно сгруппируем их во вложенном запросе с использованием агрегатных функций (МИНИМУМ, МАКСИМУМ) либо срезов.
Если ошибка вызвана некорректно заполненными дополнительными реквизитами или записями регистров, очистим повторяющиеся значения и добавим программный контроль уникальности при записи объектов.
В ситуациях, когда бизнес-логика действительно требует отображения нескольких строк на один и тот же объект (например, номенклатура в разрезе складов или характеристик), в свойствах колонок динамического списка настроим составной ключ (например, пара Ссылка + Характеристика), сняв признак единственного ключа с поля Ссылка.
Если список используется исключительно для аналитического просмотра и не требует стандартных команд редактирования, можно очистить свойство Основная таблица в свойствах динамического списка. В этом случае платформа отключает требование уникальности по полю Ссылка, однако постраничное динамическое чтение данных также перестанет работать.