Получить нужные поля элемента справочника в виде структуры

СергейТ 104 4 9

!!! ВНИМАНИЕ !!! Ещё не тестировал, написал в промежутке, между основными задачами, оттестирую и доработаю как появится время. Если кто оттестит, буду очень рад конструктивным отзывам.

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

// Функция - Получить нужные поля элемента (без табличных частей)
//
// Параметры:
//  пСсылка		 - Ссылка - Ссылка на элемент справочника
//  СписокПолей	 - Строка - Список полей разделенных запятой
// 
// Возврат:
//  Структура - Структура с заполненными значениями запрошенных полей
//
Функция ПолучитьНужныеПоляЭлемента(пСсылка, СписокПолей = "") Экспорт

	ТЗ = "ВЫБРАТЬ ПЕРВЫЕ 1
		|	ТекСправочник.Ссылка КАК Ссылка{ТекстПоляЗапроса}
		|ИЗ
		|	Справочник.ТекСправочник AS ТекСправочник
		|ГДЕ
		|	ТекСправочник.Ссылка = &Ссылка";
	ТекстШаблона = ",
		|	ТекСправочник.%1 КАК %1";
	МассивСписокПолей = СтрРазделить(СписокПолей, ",");
	ДобавленныеПоля = Новый Массив;
	ТекстПоляЗапроса = "";
	Для Каждого ТекПоле Из МассивСписокПолей Цикл
		ТекПоле = СокрЛП(ТекПоле);
		Если ТекПоле = "Ссылка" Тогда Продолжить КонецЕсли; // Поле уже есть в запросе
		Если ДобавленныеПоля.Найти(ТекПоле) Тогда Продолжить КонецЕсли;
		ДобавленныеПоля.Добавить(ТекПоле);
		ТекСтр = СтрШаблон(ТекстШаблона, ТекПоле);
		ТекстПоляЗапроса = ТекстПоляЗапроса + ТекСтр
	КонецЦикла;
	ТЗ = СтрЗаменить(ТЗ, "{ТекстПоляЗапроса}", ТекстПоляЗапроса);

	Запрос = Новый Запрос(ТЗ);
	Запрос.УстановитьПараметр("Ссылка", пСсылка);

	Выборка = Запрос.Выполнить().Выгрузить();
	Результат = Новый Структура;
	Для Каждого ТекКолонка Из Выборка.Колонки Цикл
		Результат.Вставить(ТекКолонка.Имя, Выборка[0][ТекКолонка.Имя])
	КонецЦикла;

	Возврат Результат

КонецФункции
4

Комментарии

Eremkin Igor
#1, 20 сентября 2022 18:18

Необязательно выгружать в таблицу значений, чтобы обратиться к колонкам. В РезультатеЗапроса тоже можно обойти коллекцию по колонкам


Sergei
#2, ред. 23 сентября 2022 12:22

Идея очень понравилась, спасибо. Может имеет смысл использовать ЗаполнитьЗначенияСвойств.
Набросал свой вариант для пояснения. Интересно ваше мнение.

&НаСервере
Функция ПолучитьНужныеПоляЭлемента(пСсылка, Знач СписокПолей = "") Экспорт
	
  ИмяМетаданных = пСсылка.Метаданные().Имя;
	
	// Добавляем реквизиты если не передали СписокПолей 
	Если ПустаяСтрока(СписокПолей) Тогда		
		
		// Стандартные
		Для каждого Реквизит из Справочники[ИмяМетаданных].ПустаяСсылка().Метаданные().СтандартныеРеквизиты Цикл	
			СписокПолей = СписокПолей+Реквизит.Имя+",";		
		КонецЦикла;       
		
		// Общие реквизиты	
		Для каждого Реквизит из Справочники[ИмяМетаданных].ПустаяСсылка().Метаданные().Реквизиты Цикл
		  СписокПолей = СписокПолей+Реквизит.Имя+",";	
		КонецЦикла;	

	КонецЕсли;
	
	ТЗ = "ВЫБРАТЬ ПЕРВЫЕ 1
		|	Спр.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник."+ИмяМетаданных+" AS Спр
		|ГДЕ
		|	Спр.Ссылка = &Ссылка";          
	
	Результат = Новый Структура;
	мнСтроки = СтрЗаменить(СписокПолей,",",Символы.ПС); 
	
	Для Стр=1 По СтрЧислоСтрок(мнСтроки) Цикл
		ТекПоле = СтрПолучитьСтроку(мнСтроки, Стр); 
		
		Если НЕ ПустаяСтрока(ТекПоле) Тогда
			Результат.Вставить(ТекПоле, Неопределено);
		КонецЕсли;  
		
	КонецЦикла;
	
	Если Результат.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;
	
	Запрос = Новый Запрос(ТЗ);
	Запрос.УстановитьПараметр("Ссылка", пСсылка);

	Таб = Запрос.Выполнить().Выгрузить();                 
	
	ЗаполнитьЗначенияСвойств(Результат, Таб[0].Ссылка);
	
	Возврат Результат

КонецФункции


vlhown
#3, 10 ноября 2022 16:43

А почему нельзя использовать функции БСП:
ОбщегоНазначения.ЗначениеРеквизитаОбъекта
ОбщегоНазначения.ЗначенияРеквизитовОбъекта
ОбщегоНазначения.ЗначениеРеквизитаОбъектов
ОбщегоНазначения.ЗначенияРеквизитовОбъектов


СергейТ
#4, 19 ноября 2022 10:07

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


См. также

СтруктураВидаКонтактнойИнформации (БСП)

СтруктураЗначенийПолей (БСП)

Как получить дату и время создания элемента справочника, документа по ссылке

ВидПроверки (БСП)

ОбъединитьВыделенные (БСП)

ЗаменитьВыделенные (БСП)

СнятьПризнакПредопределенныйДляВидовКонтактнойИнформации (БСП)

Количество дублей элементов справочника

ПолучитьУчастникаПоПолям (БСП)

Модератору