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