Как исправить ошибку "Обнаружено дублирование ключевых значений в колонках "ссылка"" в динамическом списке и вернуть заголовок формы в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

При работе с динамическими списками в 1С, особенно когда мы используем произвольные запросы, нередко сталкиваемся с такой неприятной ошибкой, как "Обнаружено дублирование ключевых значений в колонках "ссылка"". Эта ситуация часто возникает в паре с другой проблемой – пропаданием заголовка формы. Давайте подробно разберем, почему это происходит и как эффективно решить обе эти задачи.

Мы выясним причины возникновения дублирования ключевых значений, рассмотрим различные подходы к его устранению, а также научимся возвращать заголовок формы, который может исчезнуть при определенных настройках динамического списка. Наконец, мы обсудим, как сохранить функциональность формы, такую как открытие элемента по двойному клику, если нам пришлось отказаться от использования основной таблицы.

Причина ошибки "Обнаружено дублирование ключевых значений в колонках "ссылка""

Ошибка "Обнаружено дублирование ключевых значений в колонках "ссылка"" возникает, когда в свойствах динамического списка указана основная таблица (например, справочник), а ваш произвольный запрос возвращает несколько строк, для которых значение поля Ссылка из этой основной таблицы одинаково. Платформа ожидает, что каждая строка динамического списка, связанная с основной таблицей, будет иметь уникальную ссылку на элемент этой таблицы, чтобы корректно выполнять стандартные операции, такие как открытие формы элемента, фильтрация и сортировка.

Давайте проанализируем типовую ситуацию, когда возникает подобная ошибка. Предположим, мы имеем справочник Книги, который описывает издания, и регистр сведений МестонахождениеЭкземпляровКниг, который хранит информацию о физических экземплярах этих книг, включая их серийные номера и текущее местоположение. Если мы хотим вывести список всех экземпляров книг, включая данные из справочника и регистра, мы можем написать запрос, похожий на следующий:


ВЫБРАТЬ
    Книги.Ссылка КАК Ссылка,
    Книги.Владелец КАК Автор,
    Книги.Код КАК Код,
    Книги.Наименование КАК Название,
    Книги.ГодИздания КАК ГодИздания,
    Книги.КоличествоСтраниц КАК КоличествоСтраниц,
    МестонахождениеЭкземпляровКнигСрезПоследних.Владелец КАК Владелец,
    МестонахождениеЭкземпляровКнигСрезПоследних.СерийныйНомер КАК СерийныйНомер
ИЗ
    Справочник.Книги КАК Книги
        ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.МестонахождениеЭкземпляровКниг.СрезПоследних КАК МестонахождениеЭкземпляровКнигСрезПоследних
        ПО (МестонахождениеЭкземпляровКнигСрезПоследних.Книга = Книги.Ссылка)

В этом запросе мы используем ПОЛНОЕ СОЕДИНЕНИЕ со срезом последних регистра сведений МестонахождениеЭкземпляровКниг. Измерения регистра, как правило, определяют уникальность записи в нем. В нашем случае, это Книга и СерийныйНомер. Это означает, что для одной и той же книги (одного и того же элемента справочника Книги) может существовать несколько записей в регистре сведений, каждая из которых соответствует отдельному физическому экземпляру с уникальным серийным номером. Когда мы выполняем соединение, для каждой книги, имеющей несколько экземпляров, запрос будет возвращать несколько строк, и в каждой из этих строк поле Книги.Ссылка будет содержать одинаковое значение. Именно это дублирование значений в колонке Ссылка и приводит к ошибке, если динамический список ожидает уникальности по этому полю.

Суть проблемы заключается в том, что наша цель – показать все экземпляры книг, а не только уникальные книги. Для каждого экземпляра нам нужна отдельная строка, но платформа 1С, при наличии основной таблицы, пытается связать каждую строку списка с уникальным элементом основной таблицы.

Решение проблемы дублирования ссылок: отказ от основной таблицы

Если нам действительно необходимо отобразить все экземпляры, то есть мы сознательно идем на то, что для одной книги будет несколько строк с одинаковой ссылкой, наилучшим решением является отказ от указания основной таблицы в свойствах динамического списка. Этот подход освобождает платформу от необходимости проверять уникальность поля Ссылка, поскольку она больше не "думает", что список напрямую представляет элементы некоторого справочника или документа.

  1. Открываем форму списка: Переходим в конфигураторе к форме списка, где настроен динамический список.
  2. Находим динамический список: В дереве элементов формы выбираем сам элемент ДинамическийСписок.
  3. Свойства динамического списка: В окне свойств динамического списка находим свойство Основная таблица.
  4. Очищаем свойство: Очищаем это свойство, убедившись, что в нем ничего не указано.

После выполнения этих шагов, ошибка "Обнаружено дублирование ключевых значений в колонках "ссылка"" должна исчезнуть, так как платформа перестает применять это специфическое ограничение. Теперь динамический список будет отображать все строки, возвращаемые нашим произвольным запросом, включая те, где ссылка на книгу дублируется, что соответствует нашей бизнес-логике отображения экземпляров.

Восстановление заголовка формы после удаления основной таблицы

Когда мы убираем основную таблицу из динамического списка, платформа теряет информацию о том, какой объект конфигурации он представляет. В результате она не может автоматически сформировать заголовок формы на основе метаданных этого объекта (например, по синониму справочника). Поэтому заголовок формы просто пропадает.

Чтобы вернуть заголовок, нам необходимо установить его вручную. Мы рассмотрим два основных шага:

  1. Отключение автоматического заголовка:

    Нам нужно убедиться, что форма не пытается автоматически формировать заголовок. Для этого в свойствах формы находим флажок Автозаголовок и снимаем его. Это позволит нам полностью контролировать заголовок.

  2. Программная установка заголовка формы:

    После отключения автозаголовка, мы можем установить заголовок формы программно. Лучшее место для этого — обработчик события ПриСозданииНаСервере или ПриОткрытии формы. Мы выбираем один из этих обработчиков, поскольку они выполняются при инициализации формы, до того как она будет показана пользователю.

    Давайте посмотрим на пример кода:

    
    &НаСервере
    Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
        // Устанавливаем свой заголовок формы
        ЭтаФорма.Заголовок = "Список экземпляров книг";
    КонецПроцедуры
    

    В этом примере мы просто присваиваем строковое значение свойству Заголовок текущей формы (ЭтаФорма). Теперь, когда форма будет открыта, пользователь увидит указанный нами заголовок "Список экземпляров книг". Вы можете выбрать любой подходящий заголовок, который ясно отражает содержимое формы.

Особенности работы без основной таблицы: реализация функционала "Открытие формы элемента"

Важно понимать, что отказ от основной таблицы в динамическом списке имеет свои последствия. Стандартные механизмы платформы, связанные с основной таблицей, перестают работать автоматически. К таким механизмам относятся:

Самым частым требованием является открытие формы элемента справочника, на который ссылается текущая строка списка. Мы можем реализовать этот функционал программно, используя доступ к данным текущей строки динамического списка.

Рассмотрим, как это сделать:

  1. Создаем обработчик события для динамического списка:

    Нам потребуется обработчик события для нашего динамического списка. Наиболее подходящими являются события ПриАктивизацииСтроки (если мы хотим открывать форму при каждом выборе строки) или Выбор (если мы хотим открывать форму по двойному клику или после нажатия кнопки выбора). В данном случае, чаще всего для открытия используется двойной клик, который инициирует событие Выбор.

  2. Получаем ссылку на объект из текущей строки:

    Внутри обработчика события нам нужно получить данные текущей строки. Динамический список предоставляет доступ к этим данным через свойство ТекущиеДанные. Мы предполагаем, что в запросе динамического списка мы выбрали поле Книги.Ссылка как Ссылка, которое содержит уникальный идентификатор книги.

  3. Программное открытие формы элемента:

    После получения ссылки, мы используем глобальный метод ОткрытьФорму() для открытия формы элемента справочника. Этот метод позволяет указать имя формы и передать в неё параметры, в том числе ссылку на объект, который нужно открыть.

    Посмотрим на пример реализации для события Выбор:

    
    &НаКлиенте
    Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, СтандартнаяОбработка)
        // Отключаем стандартную обработку, чтобы наша логика сработала
        СтандартнаяОбработка = Ложь;
    
        Если Элементы.Список.ТекущиеДанные <> Неопределено Тогда
            // Получаем ссылку на книгу из текущей строки динамического списка
            ПеременнаяСсылкаНаКнигу = Элементы.Список.ТекущиеДанные.Ссылка;
    
            Если ПеременнаяСсылкаНаКнигу <> Неопределено Тогда
                // Создаем структуру параметров для открытия формы элемента
                // Ключ - это обязательный параметр для открытия формы элемента по ссылке
                ПараметрыОткрытия = Новый Структура("Ключ", ПеременнаяСсылкаНаКнигу);
    
                // Открываем форму элемента справочника "Книги"
                ОткрытьФорму("Справочник.Книги.ФормаЭлемента", ПараметрыОткрытия);
            КонецЕсли;
        КонецЕсли;
    КонецПроцедуры
    

    В этом коде мы сначала отключаем стандартную обработку (СтандартнаяОбработка = Ложь;), чтобы предотвратить любое поведение по умолчанию, которое могло бы вызвать ошибку или быть нежелательным. Затем мы проверяем, что у динамического списка есть текущие данные (Элементы.Список.ТекущиеДанные <> Неопределено) и что получена действительная ссылка на книгу. Если все условия соблюдены, мы формируем структуру параметров с ключом Ключ, в который передаем нашу ссылку. И, наконец, вызываем ОткрытьФорму(), указывая полное имя формы элемента справочника Книги ("Справочник.Книги.ФормаЭлемента") и наши параметры.

Таким образом, мы восстанавливаем критически важный функционал, который был потерян при отказе от основной таблицы, обеспечивая при этом корректное отображение всех необходимых данных, включая дублирующиеся ссылки.

Дополнительные рекомендации

Рассмотрим несколько дополнительных моментов, которые помогут вам более эффективно работать с динамическими списками и произвольными запросами.

  1. Отладка запроса:

    Если вы сталкиваетесь с неочевидными проблемами или ошибками в запросе, всегда рекомендуется выполнить запрос в консоли запросов 1С. Консоль запросов позволяет вам увидеть точный результат выполнения вашего запроса, включая все поля и строки. Это поможет вам наглядно определить, почему происходит дублирование или другие нежелательные эффекты. Вы сможете шаг за шагом анализировать части запроса, проверять условия соединений и убеждаться в корректности возвращаемых данных.

  2. Производительность динамического списка без основной таблицы:

    Важно помнить, что динамический список, у которого не указана основная таблица, может иметь сниженную производительность по сравнению с тем, у которого она указана. Это связано с тем, что платформа 1С использует оптимизированные механизмы динамического считывания и кэширования данных, когда знает, с какой таблицей он работает. Без этой информации платформа может быть вынуждена выполнять полный запрос чаще или работать с данными менее эффективно. Поэтому, если производительность становится критичной, вам, возможно, потребуется более тщательно оптимизировать сам запрос, использовать индексы или рассмотреть альтернативные подходы к отображению данных.

  3. Альтернативы для обеспечения уникальности данных (если это требуется):

    В некоторых случаях, хотя наша текущая задача требовала дублирования ссылок для отображения экземпляров, вы можете столкнуться с ситуациями, когда вам нужны именно уникальные книги, но запрос все равно выдает дубли. В таких случаях можно использовать ключевое слово РАЗЛИЧНЫЕ (DISTINCT) для поля Ссылка в запросе. Например:

    
    ВЫБРАТЬ РАЗЛИЧНЫЕ
        Книги.Ссылка КАК Ссылка,
        Книги.Наименование КАК Название
    ИЗ
        Справочник.Книги КАК Книги
        ...
    

    Однако, как мы уже отметили, для отображения экземпляров книг, это решение не подходит, так как оно уберет нужные нам дубли. Важно всегда соотносить цель отображения данных с логикой построения запроса.

  4. Организация данных в метаданных:

    Рассматривая общую архитектуру, мы могли бы рассмотреть вариант создания отдельного справочника ЭкземплярыКниг с реквизитом Книга (ссылка на Справочник.Книги) и реквизитом СерийныйНомер. В этом случае, если бы динамический список был построен на справочнике ЭкземплярыКниг, каждая строка была бы уникальным экземпляром, и проблема дублирования ссылки на основную таблицу не возникла бы. Однако, это уже вопрос проектирования метаданных, и текущее решение нацелено на исправление проблемы в существующей структуре данных.

Надеемся, что этот подробный разбор поможет вам успешно справиться с ошибкой дублирования ссылок и настройкой заголовка динамического списка в 1С.

← На главную