В процессе разработки в среде «1С:Предприятие» программисты часто сталкиваются с необходимостью декомпозиции кода. Когда одна процедура выполняет слишком много действий, её разделяют на несколько вспомогательных процедур или функций. При этом возникает типовая задача: как передать полученные или преобразованные данные из одной подпрограммы обратно в вызывающий код для дальнейшего использования (например, для установки отбора и очистки регистра сведений).
В этой статье мы подробно разберем, как правильно организовать взаимодействие между процедурами и функциями, устраним терминологическую путаницу между «ссылками» и «строками», а также рассмотрим практические сценарии очистки записей в регистре сведений по динамически полученному отбору.
Прежде чем перейти к написанию кода, проанализируем важный методологический нюанс. В обсуждениях на форумах начинающие разработчики часто называют «ссылкой» любые текстовые URL-адреса (например, http://www.jjjadsfuj.com) или имена файлов (например, dfhujs.jpg).
В платформе «1С:Предприятие» терминология строго определена:
СправочникСсылка.Номенклатура), документы (ДокументСсылка.РеализацияТоваровУслуг) и другие объектные сущности.Строка.Понимание этого различия критически важно, поскольку типы данных в регистре сведений и типы данных, используемые в отборах, должны строго совпадать. Если в регистре колонка имеет тип Строка, то и отбор мы обязаны делать по строковому значению.
---
Если перед нами стоит задача получить данные из вспомогательного алгоритма, наиболее правильным и красивым с точки зрения архитектуры решением будет оформление этого алгоритма в виде Функции. Функция, в отличие от процедуры, всегда возвращает результат своей работы в вызвавшую её программу с помощью ключевого слова Возврат.
Рассмотрим подробнее, как применить этот подход на практике. Предположим, у нас есть исходный URL-адрес, из которого во второй функции нам нужно выделить имя файла, а затем в первой процедуре выполнить очистку регистра по этому имени.
// Основная процедура, выполняющая логику очистки
Процедура ОчиститьРегистрПоИмениФайла()
// Исходные данные
ИсходныйURL = "http://www.jjjadsfuj.com/images/dfhujs.jpg";
// Вызываем функцию преобразования.
// Результат работы функции запишется в переменную ИмяФайлаДляПоиска
ИмяФайлаДляПоиска = ПолучитьИмяФайлаИзURL(ИсходныйURL);
// Проверим, удалось ли получить имя файла
Если ПустаяСтрока(ИмяФайлаДляПоиска) Тогда
ВызватьИсключение "Не удалось определить имя файла для удаления записей!";
КонецЕсли;
// Переходим к очистке регистра (подробный код очистки см. далее)
УдалитьЗаписиИзРегистра(ИмяФайлаДляПоиска);
КонецПроцедуры
// Вспомогательная функция преобразования данных
Функция ПолучитьИмяФайлаИзURL(Знач ВходнойТекст)
// Инициализируем переменную возврата
Результат = "";
// Вычленяем имя файла после последнего символа "/"
ПозицияСлеша = СтрНайти(ВходнойТекст, "/", НаправлениеПоиска.СКонца);
Если ПозицияСлеша > 0 Тогда
Результат = Сред(ВходнойТекст, ПозицияСлеша + 1);
Иначе
Результат = ВходнойТекст;
КонецЕсли;
// Возвращаем полученную строку в вызывающий код
Возврат Результат;
КонецФункции
В этом примере мы использовали ключевое слово Знач перед параметром функции. Это гарантирует, что исходная переменная ИсходныйURL в вызывающей процедуре останется неизменной, даже если внутри функции мы будем совершать манипуляции с переменной ВходнойТекст.
---
В платформе 1С по умолчанию все параметры в процедуры и функции передаются по ссылке (не путать со ссылочным типом данных в базе!). Это означает, что вызываемая процедура работает непосредственно с той же областью памяти, что и вызывающий код. Если мы изменим значение переменной внутри процедуры, оно изменится и во внешней программе.
Проанализируем этот способ на примере модификации процедуры:
Процедура ОсновнойПроцесс()
ТекущееЗначение = "http://www.jjjadsfuj.com/images/dfhujs.jpg";
// Передаем переменную в процедуру. Ключевое слово "Знач" не используется.
ПреобразоватьСсылкуВТекст(ТекущееЗначение);
// После выполнения процедуры значение переменной изменилось!
// Теперь ТекущееЗначение содержит "dfhujs.jpg"
Сообщить("Результат преобразования: " + ТекущееЗначение);
КонецПроцедуры
Процедура ПреобразоватьСсылкуВТекст(ИмяПеременной)
// Производим изменение значения прямо "внутри" переданного параметра
ПозицияСлеша = СтрНайти(ИмяПеременной, "/", НаправлениеПоиска.СКонца);
Если ПозицияСлеша > 0 Тогда
ИмяПеременной = Сред(ИмяПеременной, ПозицияСлеша + 1);
КонецЕсли;
// Оператор Возврат здесь не требуется, так как это процедура
КонецПроцедуры
Важное примечание: Хотя этот метод полностью работоспособен, использовать его для получения единственного значения не рекомендуется. Такой код сложнее читать и отлаживать, так как не всегда очевидно, какая именно процедура изменила состояние переменной. Используйте первый метод (с функциями) везде, где это возможно.
---
Теперь, когда мы научились получать итоговую строку (имя файла) в основной процедуре, разберем по шагам, как решить конечную бизнес-задачу автора темы — выполнить очистку регистра сведений по полученному отбору.
Для удаления записей из независимого регистра сведений используется объект РегистрСведенийНаборЗаписей. Чтобы очистить конкретные записи, необходимо создать набор, установить на него фильтр по ключевым полям и записать его пустым (без добавления строк в коллекцию набора).
Здесь существует важнейшее архитектурное ограничение платформы, которое часто ставит в тупик новичков: в наборе записей отбор можно установить только по Измерениям регистра сведений. По ресурсам или реквизитам прямой отбор сделать невозможно.
Рассмотрим два возможных сценария в зависимости от структуры вашего регистра.
Это самый простой случай. Если поле, по которому нужно выполнить очистку, назначено измерением регистра сведений, мы можем напрямую отфильтровать набор записей и перезаписать его.
Процедура УдалитьЗаписиИзРегистра(Знач ИмяФайлаДляПоиска)
// Создаем объект набора записей для нашего регистра
НаборЗаписей = РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей();
// Устанавливаем жесткий отбор по измерению
НаборЗаписей.Отбор.ИмяФайла.Установить(ИмяФайлаДляПоиска);
// Записываем пустой набор записей.
// Платформа автоматически удалит все строки из базы данных, соответствующие этому отбору.
НаборЗаписей.Записать(Истина); // Параметр "Истина" отвечает за замещение существующих данных
КонецПроцедуры
Если при проектировании регистра поле с именем файла было добавлено в раздел «Ресурсы» или «Реквизиты», попытка выполнить прямой отбор в наборе записей вызовет неустранимую ошибку времени выполнения.
Чтобы решить эту задачу, мы должны применить обходной путь: сначала найти все записи с помощью запроса, выбрать их ключевые измерения, а затем точечно удалить каждую найденную запись.
Процедура УдалитьЗаписиПоРесурсу(Знач ИмяФайлаДляПоиска)
// Шаг 1. Запросом получаем ключевые измерения записей, подлежащих удалению
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Регистр.КлючевоеИзмерение КАК КлючевоеИзмерение
|ИЗ
| РегистрСведений.ИмяВашегоРегистра КАК Регистр
|ГДЕ
| Регистр.ИмяФайлаРесурс = &ИмяФайла";
Запрос.УстановитьПараметр("ИмяФайла", ИмяФайлаДляПоиска);
РезультатЗапроса = Запрос.Выполнить();
// Если записи не найдены, ничего делать не нужно
Если РезультатЗапроса.Пустой() Тогда
Возврат;
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
// Шаг 2. Обходим выборку в цикле и удаляем записи через набор по их измерениям
Пока Выборка.Следующий() Цикл
НаборЗаписей = РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей();
// Отбор устанавливаем по ключевому измерению конкретной записи
НаборЗаписей.Отбор.КлючевоеИзмерение.Установить(Выборка.КлючевоеИзмерение);
// Записываем пустой набор для удаления конкретной строки
НаборЗаписей.Записать(Истина);
КонецЦикла;
КонецПроцедуры
Таким образом, мы детально разобрали, как связать логику работы нескольких подпрограмм, корректно передать текстовые параметры между ними и безопасно провести операции очистки данных в регистрах сведений 1С.