Как обратиться ко всем реквизитам объекта 1с

Получить все реквизиты и их значения для любого документа

Я
   Fanyn

12.08.15 — 13:08

Добрый день.

Мне необходимо получить все реквизиты и их значения для любого, выбранного пользователем, документа. Названия реквизитов я получила. Подскажите, пожалуйста как получить их значения и стоит ли для значений создать отдельный массив или же создать Таблицу Значений?

P.S. кодить на 1с только начала. Почти ничего не знаю :( Заранее спасибо!

&НаСервере

Функция МассивИменРеквизитовОбъекта(Объект)

        МассивИменРеквизитов = Новый Массив;

                 
            МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));

                     
        Для индекс = 0 по 1 Цикл

            КоллекцияРеквизитов = ?(индекс=0, МетаданныеОбъекта.СтандартныеРеквизиты, МетаданныеОбъекта.Реквизиты);

            Для каждого Реквизит из КоллекцияРеквизитов Цикл

                МассивИменРеквизитов.Добавить(Реквизит.Имя);

            КонецЦикла;

        КонецЦикла;

        
        Для Каждого ТабличнаяЧасть Из Объект.Метаданные().ТабличныеЧасти Цикл

        Для Каждого РеквизитТЧ ИЗ ТабличнаяЧасть.Реквизиты Цикл

                   МассивИменРеквизитов.Добавить(РеквизитТЧ.Имя);

            Сообщить(» — » + РеквизитТЧ.Имя);

        КонецЦикла;

    КонецЦикла;

    
        Возврат МассивИменРеквизитов;

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

  

Партнерская программа EFSOL Oblako

   Fanyn

1 — 12.08.15 — 13:09

Для получения названий реквизитов использую выше указанный код.

   jsmith82

2 — 12.08.15 — 13:10

Муторно как-то. Лучше звёздочкой

   1Сергей

3 — 12.08.15 — 13:12

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

   Fanyn

4 — 12.08.15 — 13:13

(2) Извините, я нуб, поэтому нужно разжевать :)

МассивИменРеквизитов.Добавить(РеквизитТЧ.*);

            

В данной строке?

   jsmith82

5 — 12.08.15 — 13:13

(4) Не-не, ты чо

   Fanyn

6 — 12.08.15 — 13:14

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

   jsmith82

7 — 12.08.15 — 13:14

Запрос = Новый Запрос();

Запрос.Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

Запрос.Текст = СтрЗаменить(Запрос.Текст, «%ИмяДок», ИмяДок);

   Fanyn

8 — 12.08.15 — 13:15

(5) мне потом эти реквизиты в файл записать нужно будет

   jsmith82

9 — 12.08.15 — 13:15

Ну, и в текст запроса можно добавить поля, которых не хватает. Не помню щас, нужно ли табличные отдельно прописывать, но там тоже будет через скобку и *.

   jsmith82

10 — 12.08.15 — 13:16

Хотя для табличных частей лучше свои отдельные таблицы. Запрос на шапку и запросы на каждую ТЧ. Выгрузка в ТЗ, доступ к именам колонок через Колонки.

   magicSan

11 — 12.08.15 — 13:19

Какая страшная логика у человека «МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));»

   jsmith82

12 — 12.08.15 — 13:20

(11) Ну да, проще Объект.Метаданные()

   magicSan

13 — 12.08.15 — 13:21

(12) Это логичнее поэтому для нормальных выглядит как проще

   magicSan

14 — 12.08.15 — 13:22

ей же написано значения объекта — как вообще до такой уйни можно было додуматся?

   Fanyn

15 — 12.08.15 — 13:24

(14) до этого я код не писала вообще, запросы строила с помощью Схемы компоновки данных. До того что есть додумалась с помощью гугла и аналогичных тем на форумах :)

   Fish

16 — 12.08.15 — 13:25

(14) Может, где-то набор новичков идёт и это у них тестовые задания? Недавно похожее что-то было:

Как получить все строковые реквизиты?

   jsmith82

17 — 12.08.15 — 13:26

Мтд = Объект.Метаданные();

Массив = Новый Массив();

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

Массив.Добавить(Структура);

Для Каждого ТабЧасть из Мтд.ТабличныеЧасти Цикл

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок.%ИмяТабЧасти КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», ИмяДок);

Текст = СтрЗаменить(Текст, «%ИмяТабЧасти», ТабЧасть.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

Массив.Добавить(Структура);

КонецЦикла;

   jsmith82

18 — 12.08.15 — 13:28

Мтд = Объект.Метаданные();

Массив = Новый Массив();

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», «Шапка», ТЗ);

Массив.Добавить(Структура);

Для Каждого ТабЧасть из Мтд.ТабличныеЧасти Цикл

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок.%ИмяТабЧасти КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Текст = СтрЗаменить(Текст, «%ИмяТабЧасти», ТабЧасть.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

Массив.Добавить(Структура);

КонецЦикла;

   Fanyn

19 — 12.08.15 — 13:33

(18) Ошибка передачи данныых.

{Форма.Форма.Форма(41)}: Ошибка при вызове метода контекста (МассивИменРеквизитовОбъекта)

    МассивРеквиз = МассивИменРеквизитовОбъекта(Док);

по причине:

Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа.

по причине:

Ошибка преобразования данных XDTO:

НачалоСвойства: ret    Форма: Элемент    Тип: {http://www.w3.org/2001/XMLSchema}anyType

по причине:

Ошибка преобразования данных XDTO:

НачалоСвойства: Value    Форма: Элемент    Тип: {http://www.w3.org/2001/XMLSchema}anyType

по причине:

Ошибка отображения типов:

Отсутствует отображение для типа ‘{http://v8.1c.ru/8.1/data/core}ValueTable’

Я с такой сталквалась, если в строке убрать Имя после точки. Я так понимаю, он передает таблицу а ждет массив?

МассивИменРеквизитов.Добавить(РеквизитТЧ.Имя);

   jsmith82

20 — 12.08.15 — 13:34

(19) не понял. код выложи функции

   Fanyn

21 — 12.08.15 — 13:39

(20) код функции полностью ваш, только добавила строку после цикла

Возврат Массив;

   Fanyn

22 — 12.08.15 — 13:42

(20)

&НаКлиенте

Процедура ВыгрузитьФайл(Команда)

        Док = Объект.Документ;

        типЗнач = ТипЗнч(Док);

        Запись = Новый ЗаписьТекста(Объект.ИмяФайла);

    Запись.ЗаписатьСтроку(Объект.Документ);

    Запись.ЗаписатьСтроку(типЗнач);

    МассивРеквиз = Новый Массив;

    МассивРеквиз = МассивИменРеквизитовОбъекта(Док);

    Для н=0 По МассивРеквиз.Количество()-1 Цикл

                    Запись.Записать(МассивРеквиз[н]+»=»+»|»);

        КонецЦикла;

    Запись.Закрыть();

КонецПроцедуры

    
&НаСервере

Функция МассивИменРеквизитовОбъекта(Объект)

    
      Мтд = Объект.Метаданные();

Массив = Новый Массив();

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», «Шапка», ТЗ);

Массив.Добавить(Структура);

Для Каждого ТабЧасть из Мтд.ТабличныеЧасти Цикл

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок.%ИмяТабЧасти КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Текст = СтрЗаменить(Текст, «%ИмяТабЧасти», ТабЧасть.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

Массив.Добавить(Структура);

КонецЦикла;

Возврат Массив;

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

   jsmith82

23 — 12.08.15 — 13:43

&НаСервере

Функция МассивИменРеквизитовОбъекта(Объект)

Мтд = Объект.Ссылка.Метаданные();

Массив = Новый Массив();

   jsmith82

24 — 12.08.15 — 13:43

Я написал для ОФ, а для УФ одну строчку изменил

   jsmith82

25 — 12.08.15 — 13:44

Хотя тоже непонятно. Что за Объект.Документ

   Fanyn

26 — 12.08.15 — 13:45

(25) Документ — это реквизит на форме обработки, документ выбираемый пользователем

   jsmith82

27 — 12.08.15 — 13:47

А, понял, ТЗ на клиент идёт

   jsmith82

28 — 12.08.15 — 13:47

ValueTable

   jsmith82

29 — 12.08.15 — 13:49

Мтд = Объект.Метаданные();

Массив = Новый Массив();

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

ТЗ = ИмяМодуля.ТаблицаЗначенийВМассив(ТЗ);

Структура = Новый Структура(«Имя, ТЗ», «Шапка», ТЗ);

Массив.Добавить(Структура);

Для Каждого ТабЧасть из Мтд.ТабличныеЧасти Цикл

Запрос = Новый Запрос();

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок.%ИмяТабЧасти КАК Док»;

Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

Текст = СтрЗаменить(Текст, «%ИмяТабЧасти», ТабЧасть.Имя);

Запрос.Текст = Текст;

ТЗ = Запрос.Выполнить().Выгрузить();

ТЗ = ИмяМодуля.ТаблицаЗначенийВМассив(ТЗ);

Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

Массив.Добавить(Структура);

   jsmith82

30 — 12.08.15 — 13:50

ИмяМодуля тут имя модуля в конфигурации, который содержит функцию ТаблицаЗначенийВМассив. Если типовая, то такой модуль должен быть. Сделай глобальный поиск. Если нет, скопируй из типовой. Там не должно быть ссылок на иные функции, а если и есть, то не больше одной-двух.

   Fanyn

31 — 12.08.15 — 14:02

(30) я пишу внешнюю обработку, функцию в модуль обработки вставила. Где теперь посмотреть имя модуля для вставленной функции (конфигурация не типовая)

   jsmith82

32 — 12.08.15 — 14:06

(31) найди в любой типовой. в УТ 11, в Бух 30

щас посмотрю у себя

   Fanyn

33 — 12.08.15 — 14:08

(32) нашла, но проблема с переносом данных между клиентом и сервером осталась..

   jsmith82

34 — 12.08.15 — 14:09

(33) Такого быть не могёт. Та же ошибка?

   jsmith82

35 — 12.08.15 — 14:10

Кинь обработку, если чо

   Fanyn

36 — 12.08.15 — 14:13

Могу, куда кинуть?

   jsmith82

37 — 12.08.15 — 14:16

Пжжи

   jsmith82

38 — 12.08.15 — 14:23

Понял, в чём ошибка. Щас

   jsmith82

39 — 12.08.15 — 14:35

Мтд = Док.Метаданные();

    Массив = Новый Массив();

    
    Запрос = Новый Запрос();

    Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

    Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

    Запрос.Текст = Текст;

    ТЗ = Запрос.Выполнить().Выгрузить();

    
    ТЗ1 = ТЗ.Скопировать();    

    Для Каждого Колонка Из ТЗ1.Колонки Цикл

        Если ТипЗнч(ТЗ[0][Колонка.Имя]) = Тип(«ТаблицаЗначений») Тогда

            ТЗ.Колонки.Удалить(Колонка.Имя);

        КонецЕсли;

    КонецЦикла;    

    ТЗ = ОбщегоНазначения.ТаблицаЗначенийВМассив(ТЗ);    

    
    Структура = Новый Структура(«Имя, ТЗ», «Шапка», ТЗ);

    Массив.Добавить(Структура);

    
    Для Каждого ТабЧасть из Мтд.ТабличныеЧасти Цикл

        
        Запрос = Новый Запрос();

        Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок.%ИмяТабЧасти КАК Док»;

        Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

        Текст = СтрЗаменить(Текст, «%ИмяТабЧасти», ТабЧасть.Имя);

        Запрос.Текст = Текст;

        ТЗ = Запрос.Выполнить().Выгрузить();

        ТЗ = ОбщегоНазначения.ТаблицаЗначенийВМассив(ТЗ);

        
        Структура = Новый Структура(«Имя, ТЗ», ТабЧасть.Имя, ТЗ);

        Массив.Добавить(Структура);

    КонецЦикла;

    
    Возврат Массив;

   jsmith82

40 — 12.08.15 — 14:35

Запрос табличные части выгружал как таблицы значений. Надо было их удалить

   jsmith82

41 — 12.08.15 — 14:36

Ну, конечно, сам сабж довольно спорен, в т.ч. под вопросом передача на клиент. Задача не ясна точно, но код рабочий

   magicSan

42 — 12.08.15 — 14:42

Какие ужасы ….. может

об=Документы.ЗаказНаряд.НайтиПоНомеру(«ПА0000050363»);

для каждого й из об.Метаданные().Реквизиты цикл

Сообщить(«»+й.имя+ » «+об[й.имя]);    

конеццикла;    

для каждого й из об.Метаданные().ТабличныеЧасти цикл

    Сообщить(» «+й.имя);

    тз=об[й.имя].выгрузить() //тч

конеццикла

   jsmith82

43 — 12.08.15 — 14:45

(42) шо это было? О_о

   magicSan

44 — 12.08.15 — 14:47

(43) Все реквизиты со значениями и тз табличных частей а чо ты там нагородил я хз — вырви глаз какой-то

   jsmith82

45 — 12.08.15 — 14:54

(44) Ну ты скажешь тоже. Вывалил в окно служебных сообщений и празднуешь?

У меня хотя бы в удобоваримый класс пакуется, с которым работать можно

   magicSan

46 — 12.08.15 — 14:58

(45) я хз куда там покавать и в каком виде это не приницпиально.

после такого

Текст = «ВЫБРАТЬ Док.* ИЗ Документ.%ИмяДок КАК Док»;

    Текст = СтрЗаменить(Текст, «%ИмяДок», Мтд.Имя);

    Запрос.Текст = Текст;

    ТЗ = Запрос.Выполнить().Выгрузить();

надо руки отрезать ……

   jsmith82

47 — 12.08.15 — 15:00

(46) чо те не нравится?

   magicSan

48 — 12.08.15 — 15:02

(47) нахера брать все значения табличных частей документов типа объекта???

   jsmith82

49 — 12.08.15 — 15:05

(48) Ессно нахера. Я же не экзамен сдаю ёптить. Написал от балды, чтобы тупо работало.

   jsmith82

50 — 12.08.15 — 15:06

У тя так вообще хрен пойми чо написано. Вывалил в стек и доволен

   jsmith82

51 — 12.08.15 — 15:06

)

   magicSan

52 — 12.08.15 — 15:08

(50)     дерево=новый ДеревоЗначений;дерево.Колонки.Добавить(«имя»);дерево.Колонки.Добавить(«зн»);    

    об=Документы.ЗаказНаряд.НайтиПоНомеру(«ПА0000050363»);

    для каждого й из об.Метаданные().Реквизиты цикл

        Сообщить(«»+й.имя+ » «+об[й.имя]);

        стр=дерево.Строки.Добавить();стр.имя=й.имя;стр.зн=об[й.имя];

    конеццикла;    

    
    для каждого й из об.Метаданные().ТабличныеЧасти цикл

        Сообщить(» «+й.имя);

        тз=об[й.имя].выгрузить(); //тч

        стр=дерево.Строки.Добавить();стр.имя=й.имя;стр.зн=тз;

    конеццикла

   magicSan

53 — 12.08.15 — 15:09

(50) У меня 4 быстро работоющих строчки а твое Уг зависает…

   jsmith82

54 — 12.08.15 — 15:09

(52) И что ты хотел этим доказать?

У меня ещё на клиент передаётся, а у тебя вырубится с ошибкой. Это тоже было в требованиях от ТС

   jsmith82

55 — 12.08.15 — 15:10

Почему зависает-то? И там, и тут обращение к серверу. Кэшируется как-то круче у тебя?

   jsmith82

56 — 12.08.15 — 15:11

Короче, раскритиковал мой код, сам ничё не предложил, чтобы отвечало требованиям, и раздулся от важности )

   magicSan

57 — 12.08.15 — 15:13

(54) то вывод не нравится то передача на сервер — детский сад. такие мелочи самому не смешно ими аргументировать?

(55) Твое угу тянет все значения табличных частей — которыхх миллионы — какой нахер кэш??? тебя просили реквизиты и значения выбраного документы — чиатать научись — я это вывожу если ыт неспособен понять 4 строчки — в ясли.

   jsmith82

58 — 12.08.15 — 15:16

(57) У тебя типа такая установка «вот вам код, если не работает или чёто не хватает, в ясли».

   Fanyn

59 — 12.08.15 — 15:16

(56) Спасибо, проблема решена :)

Однако еще вопрос ТЗ записывается в двумерный массив (видимо) и когда я циклом пытаюсь записать ее в файл то записывается просто строка «Структура». Вы не подскажете как правильнее массив разобрать по столбцам?

   jsmith82

60 — 12.08.15 — 15:18

(59) Ты как в файл записываешь? Строчно? Зачем? Сериализация не нужна? Задача просто показать, что умеешь?

   Fanyn

61 — 12.08.15 — 15:21

(60) да, сериализацию использовать нельзя и функции записи xml.

В файл записываю строки:

Имя документа

Тип документа

Реквизиты в виде: имяреквизита=значение|имя=значение| И тд

   Fanyn

62 — 12.08.15 — 15:22

(60)

Запись.ЗаписатьСтроку(Объект.Документ);

    Запись.ЗаписатьСтроку(типЗнач);

    МассивРеквиз = Новый Массив;

    МассивЗначений = Новый Массив;

    МассивЗначений = МассивЗначенийРеквизитовОбъекта(Док);

    МассивРеквиз = МассивИменРеквизитов(Док);

    Для н=0 По МассивРеквиз.Количество()-1 Цикл

        Для п=0 По МассивЗначений.Количество()-1 Цикл

                    Запись.Записать(МассивРеквиз[н]+»=»+Строка(МассивЗначений[п])+»|»);

                КонецЦикла;

                КонецЦикла;

    Запись.Закрыть();

   Fanyn

63 — 12.08.15 — 15:22

Результат записи:

Кредитный договор 000000001 от 14.03.2013 0:00:00

Кредитный договор

Проведен=Структура|Ссылка=Структура|ПометкаУдаления=Структура|Дата=Структура|Номер=Структура|Клиент=Структура|Сотрудник=Структура|СуммаКредита=Структура|Ставка=Структура|Срок=Структура|

   jsmith82

64 — 12.08.15 — 15:23

Щас скажу

   jsmith82

65 — 12.08.15 — 15:29

Мас = МассивИменРеквизитов(Док);

Для Каждого Э0 Из Мас Цикл // Шапка и Табличные части

    Для Каждого ЭММ Из Э0 Цикл // Структуры (Имя табличной части (в т.ч. Шапки) и Коллекция значений)

        ИмяТабЧасти = ЭММ.Имя;

        Коллекция = ИмяТабЧасти.ТЗ; // Массив структур

        Для Каждого Стр Из Коллекция // Структура (бывшая строка таблицы значений)

            Для Каждого КлючИЗначение Из Стр // Разбор структуры

                ИмяРеквизита = КлючИЗначение.Ключ;

                ЗначениеРеквизита = КлючИЗначение.Значение;

            КонецЦикла;

        КонецЦикла;        

    КонецЦикла;

КонецЦикла;

   jsmith82

66 — 12.08.15 — 15:30

Ну, а записать ставь там, где получаешь значение

  

Fanyn

67 — 12.08.15 — 15:48

(65) Ошибка:

{Форма.Форма.Форма(53)}: Итератор для значения не определен

    Для Каждого ЭММ ИЗ Э0 Цикл

Как обойти все элементы формы

Содержание[Убрать]

    • Как перебрать все свойства объекта формы
    • Как перебрать все свойства объекта формы

Как обойти все элементы формы

Как перебрать все свойства объекта формы

Для обращения ко всем элементам формы у формы есть свойство которое так и называется «ЭлементыФормы», обращаться к нему можно из модуля формы.

Для Каждого ТекЭлемент из ЭлементыФормы Цикл
	// ТекЭлемент.Имя
	// ТипЗнч(ТекЭлемент) - выводит тип элемента
	// Строка(ТекЭлемент) - выводит тип элемента строкой, например "ПолеВвода"
	// ТекЭлемент.Видимость
	// ТекЭлемент.Доступность
	// и т.д.
КонецЦикла;

Также к этому свойству можно обратиться через полученную форму:

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

Как перебрать все свойства объекта формы

Кроме этого можно и наоборот из формы обратиться к свойствам объекта, его реквизитам и табличным частям:


Для Каждого ТекРеквизит из Метаданные().Реквизиты Цикл
		// ТекРеквизит.Имя
КонецЦикла;

Для Каждого ТекТабЧасть из Метаданные().ТабличныеЧасти Цикл
		// ТекТабЧасть.Имя
КонецЦикла;

Но, здесь в этом случае мы узнаем только какие свойства есть, а не их значения. Чтобы узнать значения нужен конкретный объект.

Недостаточно прав для комментирования

  Как получить доступ к реквизитам объекта?

Статья носит справочный характер. Предназначена для начинающих программистов.

Получить массив реквизитов объекта можно при помощи самого объекта:

                ДокСсылка = СсылкаНаДокумент(ТипДокумента, НомерДок);
                ДокОбъект = ДокСсылка.ПолучитьОбъект();
                МассивРеквизитовОбъекта = ДокОбъект.Метаданные().Реквизиты;

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

 Для каждого Реквизит Из ДокОбъект.Метаданные().Реквизиты Цикл
                        Сообщить(Реквизит.Имя + " :" + Реквизит.Представление());
КонецЦикла;

Для того, чтобы получить значения реквизитов объекта вообще говоря надо обратиться с запросом к БД, типа:

 
Запрос = "ВЫБРАТЬ
                |       ИмяРеквизита,
                |ИЗ
                |       Объект.ТипОбъекта КАК ОбъектТипОбъекта
                |ГДЕ
                |       ОбъектТипОбъекта.Ссылка = &СсылкаНаОбъект
Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);

В запрос надо передать ссылку на объект и имя реквизита. Запрос вернет таблицу или выборку со значением реквизита.

Удобнее конечно для поиска значений реквизитов воспользоваться готовыми решениями, например фунцией ПолучитьЗначенияРеквизитов() общего модуля ОбщегоНазначения.

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

Значение реквизитов в этой функции получено через запрос к БД. Возвращаемое значение — структура (ключ-значение). Пример использования:

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

Поскольку в функцию ПолучитьЗначенияРеквизитов() во второй параметр надо передать структуру, то мы создали структуру и организовали Цикл ее инициализации данными из массива имен реквизитов объекта. Возвращает функция так же структуру (ключ-значение), с которой удобно работать. Для просмотра этой структуры можно воспользоваться циклом, либо вызвать функцию СканПростойСтруктуры(), которой передать структуру для просмотра.

 
Функция СканПростойСтруктуры(Структура)
        Для каждого Элемент из Структура Цикл
                Сообщить(Элемент.Ключ + ": " + Элемент.Значение);
        КонецЦикла;
КонецФункции

Если исследуемый объект использует так же еще и общие реквизиты, и их необходимо найти, то можно воспользоваться функцией МассивИменРеквизитовОбъекта(), которая находит не только реквизиты объекта но и общие и даже стандартные реквизиты, которые использует объект:

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

Тогда программа будет выглядеть так:

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

Вспомогательная функция:

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

Как получить значение отдельного реквизита объекта?

Иногда необязательно получать значения всего массива реквизитов. Программист как правило знает имя реквизита, значение которого необходимо получить. К отдельному реквизиту объекта можно обратиться просто по его имени:

Поставщик = ДокОбъект.Метаданные().Реквизиты.Поставщик;

Получить значение этого реквизита можно так же через запрос, написанный специально для этого реквизита. Но можно воспользоваться все той же функцией ПолучитьЗначенияРеквизитов(). Цикл для настройки структуры в этом случае не нужен, так как нам надо найти значение всего одного элемента:

 
                ДокСсылка = СсылкаНаДокумент(ТипДокумента, НомерДок);
                ДокОбъект = ДокСсылка.ПолучитьОбъект();
                                
                Организация = Строка(ДокОбъект.Метаданные().Реквизиты.Организация);
                СтруктураНастроек = Новый Структура;
                СтруктураНастроек.Вставить(Организация, Организация);
 
                ЗначенияРеквизитов = ОбщегоНазначения.ПолучитьЗначенияРеквизитов(ДокСсылка , СтруктураНастроек);
                СканПростойСтруктуры(ЗначенияРеквизитов);

Обратите внимание что здесь реквизит который необходимо найти преобразовывается к типу Строка, потому, что в структуру настроек надо передать именно строку.

Как найти имена реквизитов в таб части объекта?

Функция определяет есть ли реквизит в таб части документа:

// Позволяет определить есть ли среди реквизитов табличной части документа
// реквизит с переданным именем.
//
// Параметры:
//  ИмяРеквизита - строковое имя искомого реквизита,
//  МетаданныеДокумента - объект описания метаданных документа, среди реквизитов которого производится поиск.
//  ИмяТабЧасти  - строковое имя табличной части документа, среди реквизитов которого производится поиск
//
// Возвращаемое значение:
//  Истина - нашли реквизит с таким именем, Ложь - не нашли.
//
 
Функция ЕстьРеквизитТабЧастиДокумента(ИмяРеквизита, МетаданныеДокумента, ИмяТабЧасти) Экспорт
    ТабЧасть = МетаданныеДокумента.ТабличныеЧасти.Найти(ИмяТабЧасти);
    Если ТабЧасть = Неопределено Тогда // Нет такой таб. части в документе
        Возврат Ложь;
    Иначе
        Возврат НЕ (ТабЧасть.Реквизиты.Найти(ИмяРеквизита) = Неопределено);
    КонецЕсли;
КонецФункции

Пример использования:

 

        ИмяРеквизита = "Номенклатура";
        МетаданныеДокумента = ДокОбъект.Метаданные();
        ИмяТабЧасти = "Товары";
        
         Если ЕстьРеквизитТабЧастиДокумента(ИмяРеквизита, МетаданныеДокумента, ИмяТабЧасти) Тогда
            Сообщить("Реквизит есть!");
         Иначе
            Сообщить("Реквизита нет");
         КонецЕсли;
 

Сообщить имя реквизитов таб части:

 
Для каждого Реквизит Из ДокОбъект.Метаданные().ТабличныеЧасти.Найти("Товары").Реквизиты Цикл
        Собщить(Реквизит.Имя);
КонецЦикла; 

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

Чтобы найти значения всех реквизитов всех табличных частей объекта через запрос воспользуемся функцией

ПолучитьЗначенияРеквизитовТабЧасти().

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

 Пример использования:

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

Вспомогательная функция:

 
функция ПоказатьТаблицу(Табл)
        
        Сообщить("///Функция ПоказатьТаблицу///");
        
        Количество = Табл.Колонки.Количество();
        
        Для каждого Строка из Табл Цикл
                Для Индекс = 0 По Количество-1 Цикл 
                        Сообщить(СокрЛП(Индекс)+" "+СокрЛП(Табл.Колонки[Индекс].Имя)+ ": " + Строка[СокрЛП(Табл.Колонки[Индекс].Имя)]);
                КонецЦикла;
        КонецЦикла;
        Сообщить("///Конец Функция ПоказатьТаблицу///");
КонецФункции  

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

Имя таб части: Товары
///Функция ПоказатьТаблицу///
0 ЕдиницаИзмерения: шт
1 ЕдиницаИзмеренияМест:
2 Качество: Новый
3 Количество: 1
4 КоличествоМест: 0
5 Коэффициент: 1
6 Номенклатура: Вентилятор настольный
7 ПроцентСкидкиНаценки: 0
8 СерияНоменклатуры: Н-908, С-890 от 01.01.2003
9 СпособСписанияОстаткаТоваров: Со склада
10 СтавкаНДС: Без НДС
11 Сумма: 445,5
12 СуммаНДС: 0
13 ХарактеристикаНоменклатуры:
14 Цена: 450
15 Склад: Магазин «Бытовая техника»
16 ПроцентАвтоматическихСкидок: 1
17 УсловиеАвтоматическойСкидки: По виду дисконтных карт
18 ЗначениеУсловияАвтоматическойСкидки: Серебряная карта
19 КлючСтроки: 3
20 КлючСвязи: 0
21 ЗаказПокупателя: Заказ покупателя ТД000000001 от 08.06.2008 12:00:00
0 ЕдиницаИзмерения: шт
1 ЕдиницаИзмеренияМест:
2 Качество: Новый
3 Количество: 1
4 КоличествоМест: 0
5 Коэффициент: 1
6 Номенклатура: Набор вентиляторов
7 ПроцентСкидкиНаценки: 0
8 СерияНоменклатуры:
9 СпособСписанияОстаткаТоваров: Со склада
10 СтавкаНДС: Без НДС
11 Сумма: 1948,32
12 СуммаНДС: 0
13 ХарактеристикаНоменклатуры:
14 Цена: 1968
15 Склад: Магазин «Бытовая техника»
16 ПроцентАвтоматическихСкидок: 1
17 УсловиеАвтоматическойСкидки: По виду дисконтных карт
18 ЗначениеУсловияАвтоматическойСкидки: Серебряная карта
19 КлючСтроки: 4
20 КлючСвязи: 0
21 ЗаказПокупателя: Заказ покупателя ТД000000001 от 08.06.2008 12:00:00
///Конец Функция ПоказатьТаблицу///

Имя таб части: ВозвратнаяТара
///Функция ПоказатьТаблицу///
///Конец Функция ПоказатьТаблицу///

Имя таб части: Услуги
///Функция ПоказатьТаблицу///
///Конец Функция ПоказатьТаблицу///

Имя таб части: СоставНабора
///Функция ПоказатьТаблицу///
0 Номенклатура: Вентилятор BINATONE ALPINE 160вт, напольный ,
1 ХарактеристикаНоменклатуры:
2 СерияНоменклатуры: 01234/11020/7654321, БОЛГАРИЯ
3 Количество: 1
4 ЕдиницаИзмерения: шт
5 Склад: Магазин «Бытовая техника»
6 Качество: Новый
7 СпособСписанияОстаткаТоваров: Со склада
8 КлючСтроки: 4
9 Цена: 1068
10 КлючСвязи: 0
0 Номенклатура: Вентилятор JIPONIC (Тайв.),
1 ХарактеристикаНоменклатуры:
2 СерияНоменклатуры: 11234/11020/7654321, ТАЙВАНЬ (КИТАЙ)
3 Количество: 1
4 ЕдиницаИзмерения: шт
5 Склад: Магазин «Бытовая техника»
6 Качество: Новый
7 СпособСписанияОстаткаТоваров: Со склада
8 КлючСтроки: 4
9 Цена: 900
10 КлючСвязи: 0
///Конец Функция ПоказатьТаблицу///

Имя таб части: СерийныеНомера

///Функция ПоказатьТаблицу///
///Конец Функция ПоказатьТаблицу///

Имя таб части: СерийныеНомераСоставНабора

///Функция ПоказатьТаблицу///
///Конец Функция ПоказатьТаблицу///

Имя таб части: ДокументыРасчетовСКонтрагентом

 ///Функция ПоказатьТаблицу///
///Конец Функция ПоказатьТаблицу///

Довольно часто в алгоритмах приходится обращаться к значениям реквизитов различных объектов «через точку». При этом, если объект ссылочного типа, то возможно многократное обращение к БД. В данной статье попробуем унифицировать и оптимизировать этот процесс.

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

Задача: Описать функции позволяющие получить значения реквизитов различных объектов (независимо от типа объекта). Но ограничимся объектами метаданных конфигурации, которые могут иметь ссылочный тип данных: Справочники, Документы и т.п.

Описанные далее функции желательно располагать в общем серверном модуле без возможности вызова сервера. Если будет возможность вызывать данные функции с клиента, то злоумышленник сможет получить любые данные из базы без особого труда.

Определимся с параметрами:

  1. Объект — объект, данные которого необходимо получить;
  2. ИменаРеквизитов — Список имен реквизитов, данные которых необходимо получить. Если спиок не указан, то предполагаем, что нужно получить данные всех реквизитов;
  3. ДополнительныеРеквизиты — Структура, с помошью которой можно было бы описать дополнительные данные, которые нужно получить вместе с реквизитами объекта (без использования явных соединений с другими таблицами) или выполнение каких-то действий с полями выборки на языке запросов. В ключе элемента структуры описываем имя реквизита в общем списке реквизитов объекта, в значении — поле выборки или алгоритм обработки полей выборки на языке запросов.

Функция ДанныеРеквизитовОбъекта(Объект, ИменаРеквизитов = Неопределено,
ДополнительныеРеквизиты = Неопределено) Экспорт

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

СтруктураОбъекта = Новый Структура;
МетаданныеОбъекта = Объект.Метаданные();

Если

ИменаРеквизитов = Неопределено тогда
МассивИменРеквизитов = МассивИменРеквизитовОбъекта(Объект);
иначе
Если
ТипЗнч(ИменаРеквизитов) = Тип(«Массив») тогда
МассивИменРеквизитов = ИменаРеквизитов;
иначеЕсли
ТипЗнч(ИменаРеквизитов) = Тип(«Строка») тогда
МассивИменРеквизитов = МассивПодстрокИзСтроки(ИменаРеквизитов);
КонецЕсли;
КонецЕсли;

Если список имен не задан, то с помощью функции МассивИменРеквизитовОбъекта() получим массив имен всех реквизитов объекта (алгоритм этой функции смотри ниже).

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

Далее с помошью функции ЭтоСсылка() определим, является ли объект ссылочным типом. Для ссылочных типов значения необходимо получить из БД, в противном случае значения реквизитов хранятся в памяти.

ЭтоСсылка = ЭтоСсылка(Объект);
СсылкаОбъекта = ?(ЭтоСсылка, Объект, Объект.Ссылка);ПолучитьДанныеИзОбъекта = НЕ ЭтоСсылка;
Если
ЭтоСсылка И СсылкаОбъекта.Пустая() тогда
// это пустая ссылка (данных в базе нет)
ПолучитьДанныеИзОбъекта = Истина;
КонецЕсли;

Теперь, если данные объекта хранятся в памяти — мы можем их сразу получить, в противном случае необходио подготовиться для составления запроса к БД (переведем список имен реквизитов из типа данных Массив в тип Структура).

ОсновныеРеквизиты = Новый Структура;
Для каждого
ИмяРеквизита Из МассивИменРеквизитов Цикл
Если
ПолучитьДанныеИзОбъекта тогда
СтруктураОбъекта.Вставить(ИмяРеквизита, Объект[ИмяРеквизита]);
иначе
ОсновныеРеквизиты.Вставить(ИмяРеквизита);
КонецЕсли;
КонецЦикла;

Все готово к составлению запроса чтобы получить значения реквизитов если перед нами объект ссылочного типа, а так же для получения дополнительных реквизитов, описанных в 3-ем параметре функции. Но смысл всех этих действий есть, только если данный объект существует в БД (на него есть ссылка).

Для начала составим текст запроса для полей выборки поочередно обходя структуры Основных и Дополнительных реквизитов

Если НЕ СсылкаОбъекта.Пустая() тогда// сформируем текст выборки по реквизитам
ТекстВыборкиРеквизиты = «»;
Для
индекс = 0 по 1 Цикл
СтруктураРеквизитов = ?(индекс = 0, ОсновныеРеквизиты, ДополнительныеРеквизиты);
Если
СтруктураРеквизитов = Неопределено тогда
Продолжить;
КонецЕсли;
Для каждого
ЭлементСтруктуры из СтруктураРеквизитов Цикл
Если НЕ
МетаданныеОбъекта.ТабличныеЧасти.Найти(ЭлементСтруктуры.Ключ) = Неопределено тогда
// это имя табличной части
Продолжить;
КонецЕсли;
ТекстВыборкиРеквизиты = ТекстВыборкиРеквизиты
+ ?(ПустаяСтрока(ТекстВыборкиРеквизиты), «», «,» + Символы.ПС)
+ ?(
ЗначениеЗаполнено(ЭлементСтруктуры.Значение), ЭлементСтруктуры.Значение, ЭлементСтруктуры.Ключ)
+
» КАК « + ЭлементСтруктуры.Ключ;
КонецЦикла;
КонецЦикла;

Теперь соберем текст запроса и выполним его. Результат запроса добавим в общую структуру данных объекта

// получим реквизиты одним запросом
Если НЕ ПустаяСтрока(ТекстВыборкиРеквизиты) тогда
Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
+ ТекстВыборкиРеквизиты + «
|ИЗ
| «
+ МетаданныеОбъекта.ПолноеИмя() + «
|ГДЕ
| Ссылка = &Ссылка»
;
Запрос.УстановитьПараметр(«Ссылка», СсылкаОбъекта);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если
Выборка.Следующий() тогда
Для каждого
Колонка из РезультатЗапроса.Колонки Цикл
СтруктураОбъекта.Вставить(Колонка.Имя, Выборка[Колонка.Имя]);
КонецЦикла;
КонецЕсли;
КонецЕсли;

КонецЕсли;

Все данные получены, можно завершать функцию

Возврат СтруктураОбъекта;

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

// ДанныеРеквизитовОбъекта()

Достоинства алгоритма:

  1. Может работать с различными типами объектов конфигурации (которые могут иметь ссылки: Справочники, Документы, ПВХ и т.п.);
  2. Получение всех реквизитов за одно обращение к БД;
  3. Данные возвращаются в виде структуры, что позволяет их передать далее на клиент без преобразования;
  4. С помошью Дополнительных реквизитов можно получить вспомогательные данные (обращение к полям выборки через несколько точек) или на уровне запроса выполнить какие-то действия с данными.
  5. Наглядность кода, данные получаются одной функцией, без надобности каждый раз писать запрос к БД с обработкой результата.

Недостатки:

  1. Не реализована возможность получения табличных частей объектов

Дополнительные функции использованные в алгоритме:

// Возвращает массив имен всех реквизитов переданного объекта
//
Функция МассивИменРеквизитовОбъекта(Объект) ЭкспортМассивИменРеквизитов = Новый Массив;

Если

ТипЗнч(Объект) = Тип(«ОбъектМетаданных») тогда
МетаданныеОбъекта = Объект;
иначе
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
Если
МетаданныеОбъекта = Неопределено тогда
Возврат
МассивИменРеквизитов;
КонецЕсли;
КонецЕсли;

Для

индекс = 0 по 1 Цикл
КоллекцияРеквизитов = ?(индекс = 0, МетаданныеОбъекта.СтандартныеРеквизиты, МетаданныеОбъекта.Реквизиты);
Для Каждого
Реквизит Из КоллекцияРеквизитов Цикл
МассивИменРеквизитов.Добавить(Реквизит.Имя);
КонецЦикла;
КонецЦикла;
Для каждого
ОбщийРеквизит Из Метаданные.ОбщиеРеквизиты Цикл
Если
ИспользуетсяОбщийРеквизит(ОбщийРеквизит, МетаданныеОбъекта) тогда
МассивИменРеквизитов.Добавить(ОбщийРеквизит.Имя);
КонецЕсли;
КонецЦикла;

Возврат

МассивИменРеквизитов;

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

// Проверяет используется ли в Объекте указанный общий реквизит
//
Функция ИспользуетсяОбщийРеквизит(ОбщийРеквизит, Объект) Экспорт

Если

ТипЗнч(Объект) = Тип(«ОбъектМетаданных») тогда
МетаданныеОбъекта = Объект;
иначе
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
Если
МетаданныеОбъекта = Неопределено тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;

Если

ТипЗнч(ОбщийРеквизит) = Тип(«ОбъектМетаданных») тогда
МетаданныеОбщегоРеквизита = ОбщийРеквизит;
иначе
МетаданныеОбщегоРеквизита = Метаданные.ОбщиеРеквизиты.Найти(ОбщийРеквизит);
Если
МетаданныеОбщегоРеквизита = Неопределено тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
ЭлементСостава = МетаданныеОбщегоРеквизита.Состав.Найти(МетаданныеОбъекта);
Если
ЭлементСостава = Неопределено тогда
Возврат Ложь;
КонецЕсли;
пИспользованиеОбщегоРеквизита = Метаданные.СвойстваОбъектов.ИспользованиеОбщегоРеквизита;
Если
ЭлементСостава.Использование = пИспользованиеОбщегоРеквизита.Использовать тогда
Возврат Истина;
иначеЕсли
ЭлементСостава.Использование = пИспользованиеОбщегоРеквизита.НеИспользовать тогда
Возврат Ложь;
иначе
пАвтоИспользованиеОбщегоРеквизита = Метаданные.СвойстваОбъектов.АвтоИспользованиеОбщегоРеквизита;
Если
МетаданныеОбщегоРеквизита.АвтоИспользование = пАвтоИспользованиеОбщегоРеквизита.Использовать тогда
Возврат Истина;
иначе
Возврат Ложь;
КонецЕсли;
КонецЕсли;

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

Довольно часто в алгоритмах приходится обращаться к значениям реквизитов различных объектов «через точку». При этом, если объект ссылочного типа, то возможно многократное обращение к БД. В данной статье попробуем унифицировать и оптимизировать этот процесс.

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

Задача: Описать функции позволяющие получить значения реквизитов различных объектов (независимо от типа объекта). Но ограничимся объектами метаданных конфигурации, которые могут иметь ссылочный тип данных: Справочники, Документы и т.п.

Описанные далее функции желательно располагать в общем серверном модуле без возможности вызова сервера. Если будет возможность вызывать данные функции с клиента, то злоумышленник сможет получить любые данные из базы без особого труда.

Определимся с параметрами:

  1. Объект — объект, данные которого необходимо получить;
  2. ИменаРеквизитов — Список имен реквизитов, данные которых необходимо получить. Если спиок не указан, то предполагаем, что нужно получить данные всех реквизитов;
  3. ДополнительныеРеквизиты — Структура, с помошью которой можно было бы описать дополнительные данные, которые нужно получить вместе с реквизитами объекта (без использования явных соединений с другими таблицами) или выполнение каких-то действий с полями выборки на языке запросов. В ключе элемента структуры описываем имя реквизита в общем списке реквизитов объекта, в значении — поле выборки или алгоритм обработки полей выборки на языке запросов.

Функция ДанныеРеквизитовОбъекта(Объект, ИменаРеквизитов = Неопределено,
                               
ДополнительныеРеквизиты = Неопределено) Экспорт

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

    СтруктураОбъекта = Новый Структура;
   
МетаданныеОбъекта = Объект.Метаданные();

    Если ИменаРеквизитов = Неопределено тогда
       
МассивИменРеквизитов = МассивИменРеквизитовОбъекта(Объект);
    иначе
        Если
ТипЗнч(ИменаРеквизитов) = Тип(«Массив») тогда
           
МассивИменРеквизитов = ИменаРеквизитов;
        иначеЕсли
ТипЗнч(ИменаРеквизитов) = Тип(«Строка») тогда
           
МассивИменРеквизитов = МассивПодстрокИзСтроки(ИменаРеквизитов);
        КонецЕсли;
    КонецЕсли;

Если список имен не задан, то с помощью функции МассивИменРеквизитовОбъекта() получим массив имен всех реквизитов объекта (алгоритм этой функции смотри ниже).

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

Далее с помошью функции ЭтоСсылка() определим, является ли объект ссылочным типом. Для ссылочных типов значения необходимо получить из БД, в противном случае значения реквизитов хранятся в памяти.

    ЭтоСсылка = ЭтоСсылка(Объект);
   
СсылкаОбъекта = ?(ЭтоСсылка, Объект, Объект.Ссылка);

    ПолучитьДанныеИзОбъекта = НЕ ЭтоСсылка;
    Если
ЭтоСсылка И СсылкаОбъекта.Пустая() тогда
       
// это пустая ссылка (данных в базе нет)
       
ПолучитьДанныеИзОбъекта = Истина;
    КонецЕсли;

Теперь, если данные объекта хранятся в памяти — мы можем их сразу получить, в противном случае необходио подготовиться для составления запроса к БД (переведем список имен реквизитов из типа данных Массив в тип Структура).

    ОсновныеРеквизиты = Новый Структура;
    Для каждого
ИмяРеквизита Из МассивИменРеквизитов Цикл
        Если
ПолучитьДанныеИзОбъекта тогда
           
СтруктураОбъекта.Вставить(ИмяРеквизита, Объект[ИмяРеквизита]);
        иначе
           
ОсновныеРеквизиты.Вставить(ИмяРеквизита);
        КонецЕсли;
    КонецЦикла;

Все готово к составлению запроса чтобы получить значения реквизитов если перед нами объект ссылочного типа, а так же для получения дополнительных реквизитов, описанных в 3-ем параметре функции. Но смысл всех этих действий есть, только если данный объект существует в БД (на него есть ссылка).

Для начала составим текст запроса для полей выборки поочередно обходя структуры Основных и Дополнительных реквизитов

    Если НЕ СсылкаОбъекта.Пустая() тогда

        // сформируем текст выборки по реквизитам
       
ТекстВыборкиРеквизиты = «»;
        Для
индекс = 0 по 1 Цикл
           
СтруктураРеквизитов = ?(индекс = 0, ОсновныеРеквизиты, ДополнительныеРеквизиты);
            Если
СтруктураРеквизитов = Неопределено тогда
                Продолжить;
            КонецЕсли;
            Для каждого
ЭлементСтруктуры из СтруктураРеквизитов Цикл
                Если НЕ
МетаданныеОбъекта.ТабличныеЧасти.Найти(ЭлементСтруктуры.Ключ) = Неопределено тогда
                   
// это имя табличной части
                   
Продолжить;
                КонецЕсли;
               
ТекстВыборкиРеквизиты = ТекстВыборкиРеквизиты
                     + ?(ПустаяСтрока(ТекстВыборкиРеквизиты), «», «,» + Символы.ПС)
                     + ?(
ЗначениеЗаполнено(ЭлементСтруктуры.Значение), ЭлементСтруктуры.Значение, ЭлементСтруктуры.Ключ)
                     +
» КАК » + ЭлементСтруктуры.Ключ;
            КонецЦикла;
        КонецЦикла;

Теперь соберем текст запроса и выполним его. Результат запроса добавим в общую структуру данных объекта

        // получим реквизиты одним запросом
       
Если НЕ ПустаяСтрока(ТекстВыборкиРеквизиты) тогда
           
Запрос = Новый Запрос;
           
Запрос.Текст = «ВЫБРАТЬ
                           |»
+ ТекстВыборкиРеквизиты + «
                           |ИЗ
                           |    »
+ МетаданныеОбъекта.ПолноеИмя() + «
                           |ГДЕ
                           |    Ссылка = &Ссылка»
;
           
Запрос.УстановитьПараметр(«Ссылка», СсылкаОбъекта);
           
РезультатЗапроса = Запрос.Выполнить();
           
Выборка = РезультатЗапроса.Выбрать();
            Если
Выборка.Следующий() тогда
                Для каждого
Колонка из РезультатЗапроса.Колонки Цикл
                   
СтруктураОбъекта.Вставить(Колонка.Имя, Выборка[Колонка.Имя]);
                КонецЦикла;
            КонецЕсли;
        КонецЕсли;

    КонецЕсли;

Все данные получены, можно завершать функцию

    Возврат СтруктураОбъекта;

КонецФункции // ДанныеРеквизитовОбъекта()

Достоинства алгоритма:

  1. Может работать с различными типами объектов конфигурации (которые могут иметь ссылки: Справочники, Документы, ПВХ и т.п.);
  2. Получение всех реквизитов за одно обращение к БД;
  3. Данные возвращаются в виде структуры, что позволяет их передать далее на клиент без преобразования;
  4. С помошью Дополнительных реквизитов можно получить вспомогательные данные (обращение к полям выборки через несколько точек) или на уровне запроса выполнить какие-то действия с данными.
  5. Наглядность кода, данные получаются одной функцией, без надобности каждый раз писать запрос к БД с обработкой результата.

Недостатки:

  1. Не реализована возможность получения табличных частей объектов

Дополнительные функции использованные в алгоритме:

// Возвращает массив имен всех реквизитов переданного объекта
//
Функция МассивИменРеквизитовОбъекта(Объект) Экспорт

    МассивИменРеквизитов = Новый Массив;

    Если ТипЗнч(Объект) = Тип(«ОбъектМетаданных») тогда
       
МетаданныеОбъекта = Объект;
    иначе
       
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
        Если
МетаданныеОбъекта = Неопределено тогда
            Возврат
МассивИменРеквизитов;
        КонецЕсли;
    КонецЕсли;

    Для индекс = 0 по 1 Цикл
       
КоллекцияРеквизитов = ?(индекс = 0, МетаданныеОбъекта.СтандартныеРеквизиты, МетаданныеОбъекта.Реквизиты);
        Для Каждого
Реквизит Из КоллекцияРеквизитов Цикл
           
МассивИменРеквизитов.Добавить(Реквизит.Имя);
        КонецЦикла;
    КонецЦикла;
    Для каждого
ОбщийРеквизит Из Метаданные.ОбщиеРеквизиты Цикл
        Если
ИспользуетсяОбщийРеквизит(ОбщийРеквизит, МетаданныеОбъекта) тогда
           
МассивИменРеквизитов.Добавить(ОбщийРеквизит.Имя);
        КонецЕсли;
    КонецЦикла;

    Возврат МассивИменРеквизитов;

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

// Проверяет используется ли в Объекте указанный общий реквизит
//
Функция ИспользуетсяОбщийРеквизит(ОбщийРеквизит, Объект) Экспорт

    Если ТипЗнч(Объект) = Тип(«ОбъектМетаданных») тогда
       
МетаданныеОбъекта = Объект;
    иначе
       
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
        Если
МетаданныеОбъекта = Неопределено тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЕсли;

    Если ТипЗнч(ОбщийРеквизит) = Тип(«ОбъектМетаданных») тогда
       
МетаданныеОбщегоРеквизита = ОбщийРеквизит;
    иначе
       
МетаданныеОбщегоРеквизита = Метаданные.ОбщиеРеквизиты.Найти(ОбщийРеквизит);
        Если
МетаданныеОбщегоРеквизита = Неопределено тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЕсли;

    ЭлементСостава = МетаданныеОбщегоРеквизита.Состав.Найти(МетаданныеОбъекта);
    Если
ЭлементСостава = Неопределено тогда
        Возврат Ложь;
    КонецЕсли;

    пИспользованиеОбщегоРеквизита = Метаданные.СвойстваОбъектов.ИспользованиеОбщегоРеквизита;
    Если
ЭлементСостава.Использование = пИспользованиеОбщегоРеквизита.Использовать тогда
        Возврат Истина;
    иначеЕсли
ЭлементСостава.Использование = пИспользованиеОбщегоРеквизита.НеИспользовать тогда
        Возврат Ложь;
    иначе
       
пАвтоИспользованиеОбщегоРеквизита = Метаданные.СвойстваОбъектов.АвтоИспользованиеОбщегоРеквизита;
        Если
МетаданныеОбщегоРеквизита.АвтоИспользование = пАвтоИспользованиеОбщегоРеквизита.Использовать тогда
            Возврат Истина;
        иначе
            Возврат Ложь;
        КонецЕсли;
    КонецЕсли;

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

Andrey102019

5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

1

Как обойти все реквизиты справочника?

21.11.2019, 16:12. Показов 11898. Ответов 8

Метки 1с 8.3 оф (Все метки)


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

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Процедура КнопкаВыполнитьНажатие(Кнопка)
      МассивОбъектов = Новый Массив; 
МассивОбъектов.Добавить("Документы");
МассивОбъектов.Добавить("Справочники");
 
Для Каждого Элем из МассивОбъектов Цикл
    для Каждого ТекОбъект из Метаданные[Элем] Цикл
        Если СтрДлина(ТекОбъект) > 80 тогда
            Сообщить(ТекОбъект);    
        //что-то делаем
        КонецЕсли;
    КонецЦикла;
КонецЦикла;
    
КонецПроцедуры

Добавлено через 8 минут
видимо вот так можно обойти все реквизиты справочника, но теперь следующий вопрос, как

1C
1
2
3
для Каждого ТекОбъект из Метаданные.Справочники.Номенклатура.Реквизиты Цикл
        а=0;   
    КонецЦикла;

проверить, что текущий ТекОбъект сам является ссылкой из Справочника Номенкалатура?



0



Tklwegsd

Эксперт 1С

841 / 604 / 211

Регистрация: 24.07.2013

Сообщений: 2,101

21.11.2019, 20:28

2

1C
1
ТекОбъект.Тип.СодержитТип(Тип("СправочникСсылка.Номенклатура"))



1



Andrey102019

5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

22.11.2019, 15:03

 [ТС]

3

как из реквизита прочитать значение?

1C
1
2
3
4
5
6
7
8
9
10
11
12
Процедура КнопкаВыполнитьНажатие(Кнопка)
    ТабЗнч= Новый ТаблицаЗначений;
    ТабЗнч.Колонки.Добавить("Объект",,"Объект");
    ТабЗнч.Колонки.Добавить("Реквизит",,"Реквизит");
    ТабЗнч.Колонки.Добавить("Значение",,"Значение");
    Для Каждого ТекОбъект из Метаданные.Справочники.хххххххххххххххххх.Реквизиты Цикл
                Стр=ТабЗнч.Добавить();
            Стр.Объект="ххххххх";
            Стр.Реквизит=ТекОбъект;
            Стр.Значение=Значение(ТекОбъект); //Вот это как то надо иначе???
    КонецЦикла;
КонецПроцедуры

Добавлено через 14 минут
наверно не правильно сформулировал, можно ли выполнить проверку каждого реквизита на вхождение в них части заданной строки?

Добавлено через 8 минут
Наверно можно, если полученный реквизит поместить в запрос подстановкой, где-то такой пример попадался — подстановка параметра в запросе, как часть строки в параметре, как-то так.



0



Модератор

Эксперт 1С

3708 / 2905 / 572

Регистрация: 10.03.2011

Сообщений: 11,442

Записей в блоге: 1

23.11.2019, 02:44

4



0



5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

25.11.2019, 13:07

 [ТС]

5

Цитата
Сообщение от Dethmontt
Посмотреть сообщение

Как проверить есть ли в реквизитах справочника определенное наименование?

Зачем вы меня отправили в мою тему?



0



Модератор

Эксперт 1С

3708 / 2905 / 572

Регистрация: 10.03.2011

Сообщений: 11,442

Записей в блоге: 1

27.11.2019, 00:16

6

Цитата
Сообщение от Andrey102019
Посмотреть сообщение

как из реквизита прочитать значение?

вот так

Цитата
Сообщение от Dethmontt
Посмотреть сообщение

Andrey102019, Как проверить есть ли в реквизитах справочника определенное наименование?

Добавлено через 22 секунды

Цитата
Сообщение от Andrey102019
Посмотреть сообщение

Зачем вы меня отправили в мою тему?

Затем и отправил что вопрос повторяется…



0



5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

27.11.2019, 09:22

 [ТС]

7

Цитата
Сообщение от Dethmontt
Посмотреть сообщение

Затем и отправил что вопрос повторяется…

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



0



Модератор

Эксперт 1С

3708 / 2905 / 572

Регистрация: 10.03.2011

Сообщений: 11,442

Записей в блоге: 1

27.11.2019, 23:24

8

Цитата
Сообщение от Andrey102019
Посмотреть сообщение

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

какой вариант, почему будет огромное время… Ничего не понял



0



5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

28.11.2019, 15:34

 [ТС]

9

Цитата
Сообщение от Dethmontt
Посмотреть сообщение

какой вариант, почему будет огромное время… Ничего не понял

Если в программе проверять вхождение Текущей ссылки в Справочник Номенклатура, по данной функции НайтиПоСсылкам(<СписокСсылок>, <ОбластьПоиска>, <ВключитьОбъекты>, <ИсключитьОбъекты>) Почему может не работать Пример из Синт.пом?, то это займет много времени , близкое к минуте. Извините я кажется сам уже сбился в своих темах где и что спрашивал, из за вашей ссылки на мою же тему —

Цитата
Сообщение от Dethmontt
Посмотреть сообщение

Andrey102019, Как проверить есть ли в реквизитах справочника определенное наименование?

сам уже зациклился.
Сделал просто запрос по нужным реквизитам, получилось время близкое к секунде, возможно этого будет достаточно) Можно закрыть все темы, что бы распутаться.



0



Выборка 1С – это специальный объект в 1С 8.3, который позволяет перебрать элементы справочников, документов и прочих объектов, имеющих такую возможность.

Для создания выборки справочника следует использовать методы менеджера справочника Выбрать и ВыбратьИерархически (только для справочников с иерархией), а для создания выборки документов – Выбрать.

Например, так:

Выборка = Документы.ПродажаТоваров.Выбрать();

Или, так:

Выборка = Справочники.Контрагенты.Выбрать();

Для простой выборки.

Выборка = Справочники.Регионы.ВыбратьИерархически();

Для иерархической выборки.

Поскольку выборка это объект, предназначенный для перебора элементов, то для выполнения перебора элементов следует делать обход выборки. Обход выборки осуществляется при помощи цикла.  Обход выборки осуществляется динамически, это значит, что при создании выборки не все элементы выбираются сразу из базы данных, а получение элементов происходит порциями, частями. Для обхода используется метод выборки Следующий. Этот метод возвращает Истина, когда следующий элемент выбран, и Ложь, когда достигнут конец выборки.

Обойти выборку документов можно так:

Выборка = Документы.ПродажаТоваров.Выбрать();

Пока Выборка.Следующий() Цикл 

КонецЦикла;

А справочников, соответственно так:

Выборка = Справочники.Контрагенты.Выбрать();

Пока Выборка.Следующий() Цикл 	

КонецЦикла;

В процессе обхода выборки, мы можем обращаться напрямую ко всем реквизитам того объекта, который выбран на текущей итерации.

Выборка = Справочники.Контрагенты.Выбрать();

Пока Выборка.Следующий() Цикл 

	 Сообщить("Наименование: " + Выборка.Наименование + 
			  ",ИНН: " + Выборка.ИНН +
	 		  ",КПП: " + Выборка.КПП);

КонецЦикла;	

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

Выборка 1С

Поскольку, Контрагенты иерархический справочник, то в выборке присутствуют и группы, и элементы.

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

Можно код выше исправить следующим образом:

Выборка = Справочники.Контрагенты.Выбрать();

Пока Выборка.Следующий() Цикл 

	Если Выборка.ЭтоГруппа Тогда 
		Продолжить;
	КонецЕсли;	

	Сообщить("Наименование: " + Выборка.Наименование + 
	",ИНН: " + Выборка.ИНН +
	",КПП: " + Выборка.КПП);

КонецЦикла;	

Тогда выведутся только элементы.   

Выборка 1С

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

Выбрать(<Родитель>,<Владелец>,<Отбор>,<Порядок>)

Первый параметр позволяют формировать выборку элементов с указанным родителем, а второй с указанным владельцем. Третий параметр имеет тип Структура и позволяет отбирать элементы по определённому условию.

Например, у справочника Контрагенты имеется реквизит ТипКонтрагента, который имеет тип ссылка на перечисление ТипыКонтрагентов.

Выборка 1С

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

Отбор = Новый Структура("ТипКонтрагента",Перечисления.ТипыКонтрагентов.Покупатель);	
	
Выборка = Справочники.Контрагенты.Выбрать(,,Отбор);

Пока Выборка.Следующий() Цикл 
	
	Сообщить("Наименование: " + Выборка.Наименование + 
	",ИНН: " + Выборка.ИНН +
	",КПП: " + Выборка.КПП);
	
КонецЦикла;	

В этом случае будут отобраны только контрагенты-покупатели.

Выборка 1С

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

Также, имейте в виду, что отбор можно производить только по стандартным реквизитам Наименование, Код, а также по тем реквизитам, у которых в  свойстве Индексировать установлено значение Индексировать или Индексировать с доп. Упорядочиванием.

Иерархическая выборка справочников 1С

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

Таблица значений 1С

Для обычной выборки будет следующий код:

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

Пока Выборка.Следующий() Цикл 
	НовСтр = ТЗНоменклатура.Добавить();
	ЗаполнитьЗначенияСвойств(НовСтр,Выборка);
КонецЦикла;	

И следующий результат:

Выборка 1С

Все элементы и группы вывелись как попало, при следующей структуре справочника:

Справочник 1С

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

Выборка = Справочники.Номенклатура.ВыбратьИерархически();

Пока Выборка.Следующий() Цикл 
	НовСтр = ТЗНоменклатура.Добавить();
	ЗаполнитьЗначенияСвойств(НовСтр,Выборка);
КонецЦикла;	

Получится следующий результат:

Выборка 1С

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

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

Выборка = Справочники.Номенклатура.ВыбратьИерархически();

Пока Выборка.Следующий() Цикл 
	НовСтр = ТЗНоменклатура.Добавить();
	ЗаполнитьЗначенияСвойств(НовСтр,Выборка);
	НовСтр.Уровень = Выборка.УровеньВВыборке()
КонецЦикла;

Будет следующий результат:

Выборка 1С

Где 0 – самый высший уровень (элемент или группа не входят ни в какие группы), 1 – следующий уровень (элемент или группа входят в группу высшего уровня) и т.д.

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

Метод ПолучитьОбъект выборки

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

Например, в этом коде пытаемся всем элементам справочника Номенклатура с видом Товары, обнулить этот вид, присвоив пустую ссылку перечисления.

Выборка = Справочники.Номенклатура.Выбрать(,,Отбор);

Пока Выборка.Следующий() Цикл 
	ОбъектСправочник = Выборка.ПолучитьОбъект();
	ОбъектСправочник.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.ПустаяСсылка();
	Попытка
		ОбъектСправочник.Записать();
	Исключение
		Сообщить("Не удалось изменить вид");
	КонецПопытки;	
КонецЦикла;	

Для записи элемента использовалась попытка.

Читайте также по теме:

Объект в 1С

Ссылка в 1С

Метаданные 1С

Документы в 1С

Более подробно и основательно начальные вопросы программирования в 1С есть вы можете изучить в
Книга «Программировать в 1С за 11 шагов»

Изучайте программирование в 1С в месте с моей книгой «Программировать в 1С за 11 шагов»

Программировать в 1С за 11 шагов

Книга написана понятным и простым языком — для новичка.

  1. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  2. Научитесь понимать архитектуру 1С;
  3. Станете писать код на языке 1С;
  4. Освоите основные приемы программирования;
  5. Закрепите полученные знания при помощи задачника

О том как разрабатывать под управляемым приложением 1С, читайте в книге Книга «Основы разработки в 1С: Такси»

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

Основы разработки в 1С такси
  1. Очень доступный и понятный язык изложения
  2. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  3. Поймете идеологию управляемого приложения 1С
  4. Узнаете, как разрабатывать управляемое приложение;
  5. Научитесь разрабатывать управляемые формы 1С;
  6. Сможете работать с основными и нужными элементами управляемых форм
  7. Программирование под управляемым приложением станет понятным

Промо-код на скидку в 15% — 48PVXHeYu

Эти книги, плюс книга по программированию оперативного учета имеются в едином комплекте: комплект книг по разработке в 1С.
Только для читателей моего блога,
промо-код на скидку в 300 рублей на весь комплект: blog


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

можно оплатить вручную:

Яндекс.Деньги — 410012882996301

Подписывайтесь на мой канал в телеграмме: https://t.me/Programming1CNizamutdinov

И вступайте в мои группы:

Вконтакте: https://vk.com/1c_prosto
Фейсбуке: https://www.facebook.com/groups/922972144448119/
ОК: http://ok.ru/group/52970839015518
Твиттер: https://twitter.com/signum2009

Понравилась статья? Поделить с друзьями:
  • Как общаться с незнакомыми людьми в компании
  • Как ограничить время работы телефона андроид
  • Как ограничить время работы телефона ребенка
  • Как ограничить изменение реквизита с правами
  • Как описать модель бизнеса для банка образец