Как правильно записать значение в поле регистра сведений с ссылочным типом в 1С?

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

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

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


НаборЗаписи = РегистрыСведений.ВремяОкончанияРаботыЛаборанта.СоздатьМенеджерЗаписи;
НаборЗаписи.Пользователь = Объект.Пользователь;
МенеджерЗаписи.Записать;

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

Выясняем причину: несоответствие типов данных

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

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

Решение проблемы: получаем ссылку на элемент справочника

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

Шаг 1: Находим ссылку на элемент справочника

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

Рассмотрим пример, когда у нас есть наименование пользователя:


// Предполагаем, что Объект.Пользователь содержит строковое наименование пользователя, например "Иванов И.И."
ИмяПользователяДляПоиска = Объект.Пользователь; 

// Ищем элемент справочника "Пользователи" по его наименованию
СсылкаНаПользователя = Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователяДляПоиска);

Если бы мы знали код пользователя, мы могли бы использовать Справочники.Пользователи.НайтиПоКоду(КодПользователя).

Шаг 2: Проверяем результат поиска

Критически важно убедиться, что ссылка на элемент справочника была успешно найдена. Если метод НайтиПоНаименованию() (или НайтиПоКоду()) не найдет элемент с указанным наименованием (или кодом), он вернет значение Неопределено. Попытка присвоить Неопределено или невалидную ссылку полю ссылочного типа также приведет к тому, что данные не будут записаны или будут записаны как пустые. Поэтому всегда выполняем проверку:


Если СсылкаНаПользователя = Неопределено Тогда
    Сообщить("Внимание: Пользователь с наименованием '" + ИмяПользователяДляПоиска + "' не найден в справочнике. Запись не будет произведена.");
    Возврат; // Прерываем дальнейшее выполнение, так как ссылку получить не удалось
КонецЕсли;

Шаг 3: Присваиваем ссылку полю регистра и записываем

После того как мы успешно получили валидную ссылку на элемент справочника, мы можем присвоить ее полю регистра сведений и выполнить запись. Для этого мы будем использовать менеджер записи регистра сведений СоздатьМенеджерЗаписи().

Полный пример кода для записи:


// 1. Получаем строковое наименование пользователя из нашего объекта
//    Предполагаем, что Объект.Пользователь - это строка, содержащая наименование пользователя.
ИмяПользователяДляПоиска = Объект.Пользователь; 

// 2. Ищем ссылку на пользователя в справочнике по его наименованию
СсылкаНаПользователя = Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователяДляПоиска);

// 3. Проверяем, удалось ли найти пользователя
Если СсылкаНаПользователя = Неопределено Тогда
    Сообщить("Ошибка: Пользователь с наименованием '" + ИмяПользователяДляПоиска + "' не найден в справочнике. Запись в регистр сведений невозможна.");
    Возврат; // Выходим из процедуры
КонецЕсли;

// 4. Создаем менеджер записи регистра сведений
МенеджерЗаписи = РегистрыСведений.ВремяОкончанияРаботыЛаборанта.СоздатьМенеджерЗаписи();

// 5. Устанавливаем значения измерений для поиска существующей записи или создания новой.
//    Если поле "Пользователь" является измерением регистра, мы должны установить его,
//    чтобы система могла идентифицировать запись (для чтения или записи).
МенеджерЗаписи.Пользователь = СсылкаНаПользователя; 

//    Если в регистре есть другие измерения, которые определяют уникальность записи,
//    их также необходимо установить. Например, если есть измерение "Период":
//    МенеджерЗаписи.Период = ТекущаяДата(); 

// 6. Пробуем прочитать существующую запись
//    Это важно, если мы хотим обновить уже существующую запись с такой комбинацией измерений.
//    Если запись не будет найдена (т.е. комбинация измерений уникальна), менеджер останется пустым,
//    и последующий метод Записать() создаст новую запись.
МенеджерЗаписи.Прочитать(); 

// 7. Присваиваем значения остальным полям регистра (ресурсам или реквизитам).
//    В данном примере мы предполагаем, что "ВремяОкончания" - это ресурс, который мы хотим записать.
//    Значение берется из какого-то поля "Объекта".
МенеджерЗаписи.ВремяОкончания = Объект.ВремяОкончания; // Пример: присвоение значения из другого поля Объект

// 8. Записываем данные в регистр сведений
//    Параметр "Истина" означает запись с замещением. Если запись с такими измерениями уже существует,
//    она будет обновлена. Если не существует - будет создана новая.
Попытка
    МенеджерЗаписи.Записать(Истина); 
    Сообщить("Запись в регистр сведений успешно произведена.");
Исключение
    Сообщить("Ошибка при записи данных в регистр сведений: " + ОписаниеОшибки());
КонецПопытки;

Обратите внимание на последовательность действий: сначала получаем ссылку, проверяем ее валидность, затем устанавливаем измерения менеджера записи, читаем (если требуется обновление существующей записи), присваиваем значения и только потом записываем.

Дополнительные нюансы работы с регистрами сведений

При работе с регистрами сведений важно помнить о нескольких ключевых особенностях, которые отличают их от других объектов 1С, таких как справочники или документы:

  1. Отсутствие собственной ссылки: В отличие от элементов справочников или документов, записи регистров сведений сами по себе не имеют уникального поля Ссылка. Идентификация каждой конкретной записи происходит по комбинации значений ключевых полей, называемых измерениями.
  2. Уникальность записей по измерениям: Если поле Пользователь является измерением регистра сведений, то комбинация его значения (т.е. ссылки на пользователя) и значений других измерений (если они есть) должна быть уникальной. Если мы пытаемся записать новую запись с уже существующей комбинацией измерений, это может привести к ошибке "Запись с такими ключевыми полями уже существует" или к обновлению существующей записи, если мы предварительно ее прочитали и используем метод Записать(Истина).
  3. Менеджер записи и набор записей:
    • РегистрыСведений.<ИмяРегистра>.СоздатьМенеджерЗаписи() используется для работы с одной отдельной записью регистра сведений. С его помощью мы можем установить значения измерений, прочитать существующую запись, изменить ее ресурсы/реквизиты и записать.
    • РегистрыСведений.<ИмяРегистра>.СоздатьНаборЗаписей() используется для работы с группой записей одновременно. Это позволяет нам отфильтровать набор записей по определенным измерениям, прочитать их все, удалить, изменить и записать весь набор за одну операцию. В нашем случае, когда мы работаем с одной записью, МенеджерЗаписи является более подходящим инструментом.

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

Инструменты отладки и проверки типов

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

Во время отладки обращаем внимание на следующие моменты:

  1. Содержимое Объект.Пользователь: Убедимся, что в этом поле действительно находится строка (наименование) пользователя, которую мы ожидаем.
  2. Результат НайтиПоНаименованию(): Проверим, что возвращает функция поиска ссылки. Если она возвращает Неопределено, это означает, что элемент не был найден, и нам нужно выяснить, почему (возможно, опечатка в наименовании, отсутствие элемента в справочнике и т.д.).
  3. Типы данных: Используем встроенную функцию ТипЗнч(), чтобы проверить тип данных у значений непосредственно перед присвоением. Это поможет удостовериться, что мы пытаемся присвоить ссылку на Справочник.Пользователи полю, которое ожидает именно этот тип.
    
    // В отладчике или с помощью Сообщить()
    Сообщить("Тип значения Объект.Пользователь: " + ТипЗнч(Объект.Пользователь));
    Сообщить("Тип значения СсылкаНаПользователя: " + ТипЗнч(СсылкаНаПользователя));
    // Перед присвоением
    // Сообщить("Ожидаемый тип поля Пользователь в регистре: " + Метаданные.РегистрыСведений.ВремяОкончанияРаботыЛаборанта.Измерения.Пользователь.Тип);
    

    Если ТипЗнч(СсылкаНаПользователя) показывает "Неопределено" или любой другой тип, отличный от СправочникСсылка.Пользователи, значит, проблема в получении ссылки.

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

← На главную