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