Объектная модель схемы запроса Периодически во встроенном языке возникает необходимость изменения текста запроса в зависимости от разных алгоритмических условий. Раньше подобная задача решалась путём непосредственного формирования нужного текста запроса в виде строки. А это не всегда удобно и зачастую очень громоздко.
Теперь во встроенном языке мы реализовали объектную модель схемы запроса. Вы можете создать пустую схему запроса конструктором и загрузить в неё имеющийся текст запроса. После этого отдельные элементы текста запроса будут доступны вам как свойства объектной модели.
На рисунке ниже стрелки показывают, в каких объектах встроенного языка будут доступны те или иные элементы простого запроса, загруженного в схему:
Редактирование текста запроса с помощью объектной модели позволяет вам проще и понятнее модифицировать имеющиеся запросы. Или даже создавать их во встроенном языке «с нуля». А затем просто получать готовый текст запроса из схемы методом ПолучитьТекстЗапроса() .
Пример использования Схемы запроса Код 1C v 8.3 //Создание схемы запроса
СхемаЗапроса = Новый СхемаЗапроса;
ЗапросВыбораИзИБ = СхемаЗапроса.ПакетЗапросов[0];
//Установка свойств запроса
ЗапросВыбораИзИБ.ТаблицаДляПомещения = "ТаблицаОбороты";
ЗапросВыбораИзИБ.ВыбиратьРазрешенные = Истина;
//Добавляем операторы выбора первого запроса пакета
ОператорВыбораЗакупок = ЗапросВыбораИзИБ.Операторы[0];
ИсточникНоменклатура = ОператорВыбораЗакупок.Источники.Добавить("Справочник.Номенклатура","Товары");
//Добавляем запрос выбора из регистра закупок
ИсточникЗакупки = ОператорВыбораЗакупок.Источники.Добавить("РегистрНакопления.Закупки.Обороты","Закупки");
ИсточникЗакупки.Источник.Параметры[0].Выражение = Новый ВыражениеСхемыЗапроса("&Начало") ;
ИсточникЗакупки.Источник.Параметры[1].Выражение = Новый ВыражениеСхемыЗапроса("&Окончание") ;
ИсточникЗакупки.Источник.Параметры[2].Выражение = Новый ВыражениеСхемыЗапроса("Месяц") ;
//Меняем тип соединения
ИсточникЗакупки.Соединения[0].ТипСоединения = ТипСоединенияСхемыЗапроса.ПравоеВнешнее;
//Указываем выбираемые поля
ОператорВыбораЗакупок.ВыбираемыеПоля.Добавить("Товары.Ссылка");
ОператорВыбораЗакупок.ВыбираемыеПоля.Добавить("Закупки.Период");
ОператорВыбораЗакупок.ВыбираемыеПоля.Добавить("ЕСТЬNULL(Закупки.СуммаОборот, 0)");
ОператорВыбораЗакупок.ВыбираемыеПоля.Добавить("0");
//Указываем спевдонимы для выбранных полей
ЗапросВыбораИзИБ.Колонки[0].Псевдоним = "Номенклатура";
ЗапросВыбораИзИБ.Колонки[1].Псевдоним = "Период";
ЗапросВыбораИзИБ.Колонки[2].Псевдоним = "СуммаЗакупок";
ЗапросВыбораИзИБ.Колонки[3].Псевдоним = "СуммаПродаж";
//Добавляем отбор
ОператорВыбораЗакупок.Отбор.Добавить("НЕ Товары.ЭтоГруппа");
///////////////////////
//Выбираем данные о продажах
ОператорВыбораПродаж = ЗапросВыбораИзИБ.Операторы.Добавить();
ИсточникНоменклатура = ОператорВыбораПродаж.Источники.Добавить("Справочник.Номенклатура","Товары");
ОператорВыбораПродаж.ВыбираемыеПоля.Добавить("Товары.Ссылка");
//Добавляем источник РН и устанавливаем параметры
ИсточникПродажи =ОператорВыбораПродаж.Источники.Добавить("РегистрНакопления.Продажи.Обороты","Продажи");
ИсточникПродажи.Источник.Параметры[0].Выражение = Новый ВыражениеСхемыЗапроса("&Начало") ;
ИсточникПродажи.Источник.Параметры[1].Выражение = Новый ВыражениеСхемыЗапроса("&Окончание") ;
ИсточникПродажи.Источник.Параметры[2].Выражение = Новый ВыражениеСхемыЗапроса("Месяц") ;
ИсточникПродажи.Соединения[0].ТипСоединения = ТипСоединенияСхемыЗапроса.ПравоеВнешнее;
//Указываем отбираемые поля и устанавливаем для числовых полей соответствие с полями первого запроса
ОператорВыбораПродаж.ВыбираемыеПоля.Добавить("Продажи.Период");
ВыражениеЗакупки = ОператорВыбораПродаж.ВыбираемыеПоля.Добавить("0");
ВыражениеПродажи = ОператорВыбораПродаж.ВыбираемыеПоля.Добавить("ЕСТЬNULL(Продажи.СуммаОборот, 0)");
ЗапросВыбораИзИБ.Колонки[2].Поля.Установить(1,ВыражениеЗакупки);
ЗапросВыбораИзИБ.Колонки[3].Поля.Установить(1,ВыражениеПродажи);
//Добавляем отбор
ОператорВыбораПродаж.Отбор.Добавить("НЕ Товары.ЭтоГруппа");
//Индексируем данные
ЗапросВыбораИзИБ.Индекс.Добавить(ЗапросВыбораИзИБ.Колонки[0]);
ЗапросВыбораИзИБ.Индекс.Добавить(ЗапросВыбораИзИБ.Колонки[1]);
//Устанавливаем параметры выбора данных
ОператорВыбораПродаж.ВыбиратьРазличные = Истина;
ОператорВыбораПродаж.КоличествоПолучаемыхЗаписей = 100;
////////////////
//Второй пакет запроса
ЗапросВыбораИзВТ = СхемаЗапроса.ПакетЗапросов.Добавить();
ОператорВыбрать = ЗапросВыбораИзВТ.Операторы[0];
//Устанавливаем сформированную в прошлом запросе временную таблицу как источник
Источник = ОператорВыбрать.Источники.Добавить("ТаблицаОбороты","ТаблицаОбороты");
ОператорВыбрать.ВыбираемыеПоля.Добавить("ТаблицаОбороты.Номенклатура");
ОператорВыбрать.ВыбираемыеПоля.Добавить("ТаблицаОбороты.Период");
ОператорВыбрать.ВыбираемыеПоля.Добавить("СУММА(ТаблицаОбороты.СуммаЗакупок)");
ОператорВыбрать.ВыбираемыеПоля.Добавить("СУММА(ТаблицаОбороты.СуммаПродаж)");
//Условие отбора
ОператорВыбрать.Отбор.Добавить("СУММА(ТаблицаОбороты.СуммаЗакупок) > 0");
//Устанавливаем псевдонимы колонок
ЗапросВыбораИзВТ.Колонки[0].Псевдоним = "Номенклатура";
ЗапросВыбораИзВТ.Колонки[1].Псевдоним = "Период";
ЗапросВыбораИзВТ.Колонки[2].Псевдоним = "СуммаЗакупок";
ЗапросВыбораИзВТ.Колонки[3].Псевдоним = "СуммаПродаж";
//Порядок сортировки данных
ЗапросВыбораИзВТ.Порядок.Добавить(ЗапросВыбораИзВТ.Операторы[0].Источники[0].Источник.ДоступныеПоля[0].Поля[6]);
ЗапросВыбораИзВТ.Порядок.Добавить(ЗапросВыбораИзВТ.Колонки[1]);
//Итоги запроса
ИтогНоменклатура = ЗапросВыбораИзВТ.КонтрольныеТочкиИтогов.Добавить(ЗапросВыбораИзВТ.Колонки[0]);
ИтогНоменклатура.ТипКонтрольнойТочки = ТипКонтрольнойТочкиСхемыЗапроса.ТолькоИерархия;
ЗапросВыбораИзВТ.ОбщиеИтоги =Истина;
ЗапросВыбораИзВТ.ВыраженияИтогов.Добавить(ЗапросВыбораИзВТ.Колонки[2]);
ЗапросВыбораИзВТ.ВыраженияИтогов.Добавить(ЗапросВыбораИзВТ.Колонки[3]);
////////////////
//Последний запрос пакета - удаление временной таблицы
ЗапросУничтоженияВТ = СхемаЗапроса.ПакетЗапросов.Добавить(Тип("ЗапросУничтоженияТаблицыСхемыЗапроса"));
ЗапросУничтоженияВТ.ИмяТаблицы = "ТаблицаОбороты";
// ДАЛЕЕ ЕСЛИнам необходимо этот запрос модифицировать дальше в зависимости от настроек.
// Рассмотрим несколько примеров модификация нашего пакета из 3х запросов:
// Пример 1. Допустим, у нас есть переменные "Организация" и "Склад". И в случае, если они заполнены, нам необходимо добавить в отбор данных условия на эти переменные.
Если ЗначениеЗаполнено(Организация) Тогда
ОператорВыбораЗакупок.Отбор.Добавить("Закупки.Организация = &Организация");
ОператорВыбораПродаж.Отбор.Добавить("Продажи.Организация = &Организация");
КонецЕсли;
Если ЗначениеЗаполнено(Склад) Тогда
ОператорВыбораЗакупок.Отбор.Добавить("Закупки.Склад = &Склад");
ОператорВыбораПродаж.Отбор.Добавить("Продажи.Склад = &Склад");
КонецЕсли;
// Пример 2. Нам нужно отобрать товары, для которых последняя цена выше 1000руб. Т.е. необходимо
// 1. Добавить в текст запроса выбор во временную таблицу из регистра цен номенклатуры, по которой цены выше 1000руб.
// 2. Добавить при выборе данных условия по этой временной таблице в оба запроса выбора данных (закупки и продажи).
// Как вклиниваться в текстовый запрос для выполнения этих действий, вы пожете представить самостоятельно.
// Программно мы просто добавляем строки кода:
//Добавляем временную таблицу
ЗапросИзРегистраЦен = СхемаЗапроса.ПакетЗапросов.Добавить();
//Настраиваем временную таблицу
ЗапросИзРегистраЦен.ТаблицаДляПомещения = "ВТ_ЦеныНоменклатуры";
ОператорВыбрать = ЗапросИзРегистраЦен.Операторы[0];
Источник = ОператорВыбрать.Источники.Добавить("РегистрСведений.ЦеныНоменклатуры.СрезПоследних","ЦеныНоменклатурыСрезПоследних");
ОператорВыбрать.ВыбираемыеПоля.Добавить("ЦеныНоменклатурыСрезПоследних.Номенклатура");
ОператорВыбрать.Отбор.Добавить("ЦеныНоменклатурыСрезПоследних.Цена > &Цена");
//Сдвигаем новую табличку перед запросами выбора данных
СхемаЗапроса.ПакетЗапросов.Сдвинуть(СхемаЗапроса.ПакетЗапросов.Индекс(ЗапросИзРегистраЦен),0);
//Добавляем условия в исходные запросы
ОператорВыбораЗакупок.Отбор.Добавить("Закупки.Номенклатура В (ВЫБРАТЬ ВТ_ЦеныНоменклатуры.Номенклатура ИЗ ВТ_ЦеныНоменклатуры КАК ВТ_ЦеныНоменклатуры)");
ОператорВыбораПродаж.Отбор.Добавить("Продажи.Номенклатура В (ВЫБРАТЬ ВТ_ЦеныНоменклатуры.Номенклатура ИЗ ВТ_ЦеныНоменклатуры КАК ВТ_ЦеныНоменклатуры)");
// Еще один небольшой пример использования схемы запроса. Формирование запроса, выполняющего поиск задвоенных значений предопределенных данных.
// Без обращения к метаданным формирует один общий запрос ко всем справочникам, планам счетов, ПВХ, ПВР вцелом по конфигурации.
СхемаЗапроса = Новый СхемаЗапроса;
КоллекцияОператоры = СхемаЗапроса.ПакетЗапросов[0].Операторы;
Для каждого ГруппаТаблиц Из СхемаЗапроса.ПакетЗапросов[0].ДоступныеТаблицы Цикл
Если ГруппаТаблиц.Представление = "Справочники"
ИЛИ ГруппаТаблиц.Представление = "ПланыСчетов"
ИЛИ ГруппаТаблиц.Представление = "ПланыВидовРасчета"
ИЛИ ГруппаТаблиц.Представление = "ПланыВидовХарактеристик" Тогда
Для каждого Таблица Из ГруппаТаблиц.Состав Цикл
Для каждого ПолеТаблицы Из Таблица.Поля Цикл
Если ПолеТаблицы.Имя = "ИмяПредопределенныхДанных" Тогда
НовыйОператор = КоллекцияОператоры.Добавить();
НовыйИсточник = НовыйОператор.Источники.Добавить(Таблица,"СправочникИмя");
НовыйОператор.ВыбираемыеПоля.Добавить(""""+Таблица.Имя+"""");
НовыйОператор.ВыбираемыеПоля.Добавить("КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СправочникИмя.ИмяПредопределенныхДанных)" );
НовыйОператор.Группировка.Добавить("СправочникИмя.ИмяПредопределенныхДанных");
НовыйОператор.Отбор.Добавить("СправочникИмя.Предопределенный");
НовыйОператор.Отбор.Добавить("КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СправочникИмя.Ссылка) > 1");
Продолжить;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Категория:
Запросы Получение уникального идентификатора ссылки в СКД Как известно, с помощью языка запросов 1С получить уникальный идентификатор объекта ссылочного типа на данный момент нельзя. Но используя возможность СКД обращаться к внешним функциям можно получить строковое представление уникального идентификатора ссылки. Для этого необходимо использовать глобальную функцию XMLСтрока в вычисляемых полях в макете схемы компоновки.
Далее проведем эксперимент по быстродействию получения результата через запрос с последующей обработкой выборки и вариантов с использованием СКД.
Рассмотрим два случая - вывод в табличный документ и формирование текстового документа.
Так же в случае с СКД мы можем создать схему компоновки программно или использовать готовую. Результат работы СКД так же можно обойти в цикле, либо вывести в таблицу значений с последующей обработкой. Для экспериментов будет использоваться платформа 8.3, конфигурация УТ11 (файловая), справочник "КлассификаторБанковРФ", более 4000 элементов.
Схему компоновки и макет можно посмотреть, скачав обработку (ссылка в конце).
Код 1C v 8.2 УП &НаКлиентеНаСервереБезКонтекста
Функция ПолучитьТекстЗапроса()
Возврат "ВЫБРАТЬ
| КлассификаторБанковРФ.Ссылка,
| КлассификаторБанковРФ.Наименование
|ИЗ
| Справочник.КлассификаторБанковРФ КАК КлассификаторБанковРФ";
КонецФункции // ПолучитьТекстЗапроса()
&НаСервере
Функция ПолучитьСхемуОбработки()
Возврат РеквизитФормыВЗначение("Отчет").ПолучитьМакет("Макет");
КонецФункции
&НаСервереБезКонтекста
Функция ПолучитьСхемуКомпоновки()
Схема = Новый СхемаКомпоновкиДанных;
ИсточникДанных = Схема.ИсточникиДанных.Добавить();
ИсточникДанных.Имя = "Источник";
ИсточникДанных.ТипИсточникаДанных = "Local";
НаборДанных = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборДанных.Имя = "НаборДанных";
НаборДанных.ИсточникДанных = "Источник";
НаборДанных.Запрос = ПолучитьТекстЗапроса();
НаборСсылка = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
НаборСсылка.Поле = "Ссылка";
НаборСсылка.ПутьКДанным = "Ссылка";
НаборНаименование= НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
НаборНаименование.Поле = "Наименование";
НаборНаименование.ПутьКДанным = "Наименование";
ПолеИД = Схема.ВычисляемыеПоля.Добавить();
ПолеИД.Выражение = "XMLСтрока(Ссылка)";
ПолеИД.Заголовок = "ИД";
ПолеИД.ПутьКДанным = "ИД";
СтрокаТЗ = Схема.НастройкиПоУмолчанию.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
СтрокаТЗ.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
ЭлементыВыбора = Схема.НастройкиПоУмолчанию.Выбор.Элементы;
ПолеСсылка = ЭлементыВыбора.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ПолеСсылка.Поле = Новый ПолеКомпоновкиДанных("Ссылка");
ПолеНаименование = ЭлементыВыбора.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ПолеНаименование.Поле = Новый ПолеКомпоновкиДанных("Наименование");
ПолеИД = ЭлементыВыбора.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ПолеИД.Поле = Новый ПолеКомпоновкиДанных("ИД");
Возврат Схема;
КонецФункции
&НаСервереБезКонтекста
Функция ЗаполнитьПоКомпоновкеПрямойОбход(Схема)
Док = Новый ТекстовыйДокумент;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(Схема, Схема.НастройкиПоУмолчанию,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет,,, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(Новый ТаблицаЗначений);
ПроцессорВывода.НачатьВывод();
Пока Истина Цикл
ЭлементКомпоновки = ПроцессорКомпоновки.Следующий();
Если ЭлементКомпоновки = Неопределено Тогда
Прервать;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементКомпоновки);
Если ЭлементКомпоновки.Макет = "Макет2" И ЭлементКомпоновки.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоИКонец Тогда
Док.ДобавитьСтроку(ЭлементКомпоновки.ЗначенияПараметров.П2.Значение + ";" + ЭлементКомпоновки.ЗначенияПараметров.П3.Значение);
КонецЕсли;
КонецЦикла;
ТЗ = ПроцессорВывода.ЗакончитьВывод();
Возврат Док;
КонецФункции // ЗаполнитьПоКомпоновкеПрямойОбход()
&НаСервере
Функция ЗаполнитьОбходТЗ(ИспользоватьСхемуОбработки)
Если ИспользоватьСхемуОбработки Тогда
Схема = ПолучитьСхемуОбработки();
Иначе
Схема = ПолучитьСхемуКомпоновки();
КонецЕсли;
Возврат ЗаполнитьПоКомпоновкеОбходТЗ(Схема);
//Возврат ЗаполнитьПоКомпоновкеОбходТЗ(?(ИспользоватьСхемуОбработки, ПолучитьСхемуОбработки(), ПолучитьСхемуКомпоновки()));
КонецФункции // ЗаполнитьОбходТЗ()
&НаСервере
Функция ЗаполнитьПрямойОбход(ИспользоватьСхемуОбработки)
Если ИспользоватьСхемуОбработки Тогда
Схема = ПолучитьСхемуОбработки();
Иначе
Схема = ПолучитьСхемуКомпоновки();
КонецЕсли;
Возврат ЗаполнитьПоКомпоновкеПрямойОбход(Схема);
//Возврат ЗаполнитьПоКомпоновкеПрямойОбход(?(ИспользоватьСхемуОбработки, ПолучитьСхемуОбработки(), ПолучитьСхемуКомпоновки()));
КонецФункции // ЗаполнитьОбходТЗ()
&НаСервереБезКонтекста
Функция ЗаполнитьПоКомпоновкеОбходТЗ(Схема)
Док = Новый ТекстовыйДокумент;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(Схема, Схема.НастройкиПоУмолчанию,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет,,, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(Новый ТаблицаЗначений);
ТЗ = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Для Каждого СтрокаТЗ Из ТЗ Цикл
Док.ДобавитьСтроку(СтрокаТЗ.Наименование + ";" + СтрокаТЗ.ИД);
КонецЦикла;
Возврат Док;
КонецФункции // ЗаполнитьПоКомпоновкеОбходТЗ()
&НаСервереБезКонтекста
Функция ЗаполнитьПоЗапросу()
Док = Новый ТекстовыйДокумент;
Запрос = Новый Запрос(ПолучитьТекстЗапроса());
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
Док.ДобавитьСтроку(Результат.Наименование + ";" + XMLСтрока(Результат.Ссылка));
КонецЦикла;
Возврат Док;
КонецФункции // ЗаполнитьПоЗапросу()
&НаСервере
Процедура ЗаполнитьТабДокСхема(ИспользоватьСхемуОбработки)
Если ИспользоватьСхемуОбработки Тогда
Схема = ПолучитьСхемуОбработки();
ТабДок = ТабДок1;
Иначе
Схема = ПолучитьСхемуКомпоновки();
ТабДок = ТабДок2;
КонецЕсли;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(Схема, Схема.НастройкиПоУмолчанию);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет,,, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры // ЗаполнитьТабДокСхема()
&НаСервере
Процедура ЗаполнитьТабДокЗапрос()
Макет = РеквизитФормыВЗначение("Отчет").ПолучитьМакет("Отчет");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Запрос = Новый Запрос(ПолучитьТекстЗапроса());
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
ОбластьСтрока.Параметры.Заполнить(Результат);
ОбластьСтрока.Параметры.ИД = XMLСтрока(Результат.Ссылка);
ТабДок3.Вывести(ОбластьСтрока);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьТабДокСхема(Истина);
ЗаполнитьТабДокСхема(Ложь);
ЗаполнитьТабДокЗапрос();
Т1 = ЗаполнитьПоЗапросу();
Т2 = ЗаполнитьОбходТЗ(Ложь);
Т3 = ЗаполнитьОбходТЗ(Истина);
Т4 = ЗаполнитьПрямойОбход(Ложь);
Т5 = ЗаполнитьПрямойОбход(Истина);
КонецПроцедуры
По результатам замера производительности видно, что вывод результата в табличный документ происходит быстрее при использовании СКД, причем вариант с программным созданием схемы отрабатывает несколько быстрее.
В тоже время вывод результатов в текстовый документ отрабатывает быстрее для запроса.
Программное создание схемы компоновки отработало быстрее, чем получение макета схемы.
Источник
Категория:
Схема Компоновки Данных