Каталог решений - Как отказаться от использования НайтиПоНаименованию() и НайтиПоКоду() в уже работающих наполненных базах при дальнейшей разработке.

Как отказаться от использования НайтиПоНаименованию() и НайтиПоКоду() в уже работающих наполненных базах при дальнейшей разработке.

Как отказаться от использования НайтиПоНаименованию() и НайтиПоКоду() в уже работающих наполненных базах при дальнейшей разработке.

В наличии

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

Категория:

Описание

Если вы встречали в коде конструкции типа

Справочники.Номенклатура.НайтиПоНаименованию("Большая круглая фиговина 1мм");
Документы.РеализацияТоваровУслуг.НайтиПоКоду("00000000001");

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

Лично я не один и даже не десять раз наталкивался на последствия хардкодинга в виде использования функций НайтиПоКоду(), НайтиПоНаименованию() и НайтиПоНомеру() с зашитыми в коде значениями. Последствия всегда плачевные, их диапазон весьма широк — недоумение «почему оно не работает» или «почему в документе пустые реквизиты, вчера всё работало», необходимость куда-то лезть и менять прописанные значения, красные глаза от поиска в километрах кода той самой заветной строчки, а иногда и возможность интересно провести ночь за удалением/исправлением неправильно перенесённых/сгенерированных данных.

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

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

 

Первый способ,

который подсказывает Капитан Очевидность — это использование предопределённых элементов. Если вам в коде нужно сослаться на валюту Рубль и ни на какую другую — создайте предопределённый Рубль в справочнике «Валюты». На этом способе даже не останавливаюсь, потому что он, надеюсь, понятен всем. Минус такого способа в том, что он не применим в базе, которая уже наполнена данными. Т.е. если в базе уже есть непредопределённый Рубль, то вы же не будете добавлять предопределённый и перебивать все ссылки в базе с одного Рубля на другой? Очень надеюсь, что такая мысль не придёт вам в голову.

 

Второй способ.

Для версий ниже 8.3. Долгое время и весьма успешно для искоренения НайтиПо…() из написанного до меня кода я использовал ПланВидовХарактеристик и РегистрСведений.

Допустим, какой-то нехороший человек до вас в коде написал:

 

Документ.Валюта = Справочники.Валюты.НайтиПоНаименованию("Рубль");

 

Тогда вы берёте и, не переставая молиться за спасение души этого человека, создаёте ПланВидовХарактеристик «СлужебныеПеременные» (типы значений выбираете в нашем случае справочник «Валюты») и РегистрСведений «ЗначенияСлужебныхПеременных» (непериодический, неподчинённый) с измерениями «Переменная» (тип ПВХСсылка.СлужебныеПеременные) и «Значение» (тип Характеристика.СлужебныеПеременные). Дальше в ПВХ создаёте предопределённый элемент Валюта_Рубль, а в РС запись — Валюта_Рубль = Рубль (выбираете из справочника «Валюты»). После этого идёте в код и пишете

//Документ.Валюта = Справочники.Валюты.НайтиПоНаименованию("Рубль");
Документ.Валюта = ПолучитьЗначениеСлужебнойПеременной(ПредопределенноеЗначение("ПланВидовХарактеристик.СлужебныеПеременные.Валюта_Рубль"));

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

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

Плюс такого подхода — это совершенно отдельно стоящий механизм, который не влияет на типовые механизмы и не затрагивает типовые объекты метаданных.

Минус — да, должен быть заполнен регистр сведений, без него никуда. Здесь можно посоветовать при начале работы системы под админскими правами сверять количество служебных переменных в плане видов характеристик и количество записей в регистре «Значения служебных переменных» и, если какие-то переменные не заполнены — выдавать что-нибудь грозное и устрашающее, пусть заполняют. Ещё можно создать обработку автоматического заполнения регистра. Как заполнять? А с помощью тех самых ненавистных мне НайтиПоКоду(«000001») — а что делать, ради такого благого дела можно их и потерпеть ещё разик 🙂 Для особо пугливых можно просто использовать этот механизм как основной, а НайтиПо…() не удалять, а оставить как дублирующий, на всякий случай.

 

Третий способ.

Для версий от 8.3 — неожиданное продолжение первого способа с помощью новых технологий.

В платформе 8.3 появилась интересная возможность переназначать, удалять и всячески извращаться над предопределёнными элементами. Т.е. тот самый Рубль, который непредопределённый, можно просто сделать предопределённым! Не знаю как вы, я вначале не поверил, когда узнал, что так можно. Но оказалось, что да, действительно, докатились, теперь и в мире 1С нет ничего постоянного и надёжного. Но в данном случае это даже хорошо — мы можем, обойдясь подножными средствами, отделаться от НайтиПо…()

Итак, что нужно?

Идём в конфигуратор, открываем нужный объект метаданных (наш справочник «Валюты»), идём в предопределённые, добавляем новый предопределённый Рубль, обязательно задаём ему вручную какой-нибудь незанятый код.

Теперь создаём новую обработку, в ней форму, в форме создаём процедуру ПриСозданииНаСервере(), там пишем

 

&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
	
	// лишаем предопределённый рубль его предопределённости
	Валюта = Справочники.Валюты.НайтиПоКоду([Код_Предопределённого_Рубля]).ПолучитьОбъект();
	Валюта.ИмяПредопределенныхДанных = “”;
	Валюта.Записать();
	
	// освободившуюся предопределённость отдаём старому рублю
	Валюта = Справочники.Валюты.НайтиПоКоду([Код_НЕ_Предопределённого_Рубля]).ПолучитьОбъект();
	Валюта.ИмяПредопределенныхДанных = “Рубль”;
	Валюта.Записать();
	
КонецПроцедуры

 

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

 

UPD:

Навеяно комментариями к статье.

В комментариях многие предлагают использовать метод ПолучитьСсылку(«уид-того-что-нам-надо») с зашитым в тексте программы УИДом. Но, как и любая разновидность Г-кода, хардкодинг (зашивание значений в код) имеет множество недостатков и кажется мне непримлиемой. Фактически предлагается избавиться от одного хардкодинга другим, мотивируя это тем, что, якобы уид ссылки никогда не меняется. На деле же, как и любой Г-код, это — быстрая и дешёвая заплатка, сделанная на коленке.

Во-первых, УИД может поменяться — не УИД той ссылки, которую мы используем, а сам элемент, который мы используем. Например, раньше нам нужен был УИД элемента справочника Типы цен «Розничная», а теперь нужен «Розничная СПБ». Конечно, нужно лезть в код и менять, а до того система будет работать не так, как нужно.

Во-вторых, можно забыть о тестовых базах — не получится просто взять cf от конфигурации и накатить её на демо-базу и вести разработку там, просто перенося изменения в рабочую. Как раз сейчас работаю на проекте, где изначально было две базы — рабочая и тестовая, создавались они не из одного dt, а независимо друг от друга, соответственно, все УИДы разные. Пытаюсь вести разработку в демо-базе, но каждый раз, когда на тыкаюсь на все эти УИДы, не могу не пожелать долгой и мучительной смерти тому, кто всё это рисовал.

В-третьих, строка

ПолучитьЗначениеПеременной(ПредопределенноеЗначение("ПВХ.Переменные.ТипЦены_Розничная"))

явно читабельнее, чем строка

Справочники.ТипыЦен.ПолучитьСсылку("с3фацфмыф-ф23аф23аф0-2й3укфафц0-23к2к")

Кто-то писал, что это исправляется добавлением комментария, но всё это из области фантастики — я в своей работе ни разу не встречал комментарий рядом с УИДом.

has been added to your cart:
Оформление заказа