Переход с платформы 1С v8.х на «семерку» (1С:Предприятие 7.7) часто вызывает у разработчиков легкое замешательство. Отсутствие привычной консоли запросов, невозможность создавать табличные части у справочников «из коробки» и особенности работы с контекстом формы — это лишь малая часть айсберга, с которым сталкивается программист. Рассмотрим, как решить классическую задачу группировки данных по реквизиту справочника для внешнего отчета, разберем причины ошибок при попытке работы с экранными таблицами и изучим изящные методы оптимизации интерфейса и кода.
Если нам необходимо получить данные справочника, сгруппированные по определенному реквизиту, самым быстрым и правильным решением будет использование встроенного языка запросов 1С 7.7. В отличие от версии 8.х, здесь используется свой синтаксис, однако визуальный конструктор запросов отлично помогает быстро набросать структуру.
Проанализируем пример построения такого запроса. Предположим, у нас есть справочник «Сотрудники», и нам нужно сгруппировать их по реквизиту «Должность»:
Перем Запрос, ТекстЗапроса, Таб;
// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Обрабатывать НеПомеченныеНаУдаление;
|Без итогов;
|Сотрудники = Справочник.Сотрудники.ТекущийЭлемент;
|Должность = Справочник.Сотрудники.Должность;
|Группировка Должность;
|Группировка Сотрудники без групп;
|"//}}ЗАПРОС
;
// Выполняем запрос и проверяем на ошибки
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Предупреждение("Ошибка при выполнении запроса!");
Возврат;
EndЕсли;
// Инициализируем выходную таблицу (макет)
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяTable("Сформировать");
Таб.ВывестиСекцию("Заголовок");
// Обходим результаты по группировкам
Пока Запрос.Группировка("Должность") = 1 Цикл
// Здесь мы позиционируемся на конкретной должности
Таб.ВывестиСекцию("СекцияДолжность");
Пока Запрос.Группировка("Сотрудники") = 1 Цикл
// Здесь мы обходим сотрудников внутри текущей должности
Таб.ВывестиСекцию("СтрокаСотрудника");
КонецЦикла;
КонецЦикла;
Таб.ТолькоПросмотр(1);
Таб.Показать("Отчет по сотрудникам", "");
Обратим внимание на важную деталь: в тексте запроса мы явно указали переменную Сотрудники через ТекущийЭлемент. Это позволяет нам получать ссылку на сам элемент справочника внутри цикла обхода группировки.
Если по каким-то причинам использование объекта Запрос нецелесообразно (например, требуется выполнять сложные интерактивные манипуляции с элементами «на лету»), мы можем применить объектную выборку. Для того чтобы выборка происходила в порядке определенного реквизита, в 1С 7.7 существует метод ПорядокРеквизита().
Выясним причину, почему этот метод может вызывать ошибку времени выполнения. Для того чтобы платформа могла сортировать выборку по конкретному реквизиту, в Конфигураторе для этого реквизита обязательно должно быть установлено свойство (флаг) «Сортировка». Если этот флаг не взведен, база данных физически не имеет нужного индекса, и метод вернет ошибку.
Посмотрим на пример кода выборки клиентов с сортировкой по реквизиту Дом:
Спр = СоздатьОбъект("Справочник.Клиенты");
// Устанавливаем сортировку по реквизиту "Дом"
// Важно: в Конфигураторе у реквизита "Дом" должен стоять флаг "Сортировка"!
Спр.ПорядокРеквизита("Дом");
Спр.ВыбратьЭлементы();
ДомДляСравнения = "";
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// Пропускаем группы и помеченные на удаление элементы
Если (Спр.ЭтоГруппа() = 1) Или (Спр.ПометкаУдаления() = 1) Тогда
Продолжить;
КонецЕсли;
// Эмулируем группировку в цикле
Если ДомДляСравнения <> Спр.Дом Тогда
ДомДляСравнения = Спр.Дом;
// Здесь мы зафиксировали смену группы (новый дом)
Сообщить("--- Новый дом: " + ДомДляСравнения);
КонецЕсли;
// Выводим информацию по конкретному клиенту
Сообщить(" Клиент: " + Спр.Наименование + ", кв. " + Спр.Кв);
КонецЦикла;
Если у вас нет возможности или прав изменять конфигурацию (включать индексацию реквизита), то единственным выходом при объектном обходе будет выгрузка результатов в ТаблицуЗначений с последующим вызовом метода Сортировать().
Очень частая ошибка начинающих разработчиков в 1С 7.7 — попытка программного обращения к элементам формы (диалога) при работе с объектами базы данных. Рассмотрим ситуацию: на форме элемента справочника расположена таблица с идентификатором Ж. Разработчик пытается написать в коде внешнего отчета:
Колво = Спр.Ж.КоличествоСтрок(); // Ошибка!
Разберем, почему данный код принципиально неработоспособен в среде 1С 7.7:
ТаблицаЗначений.СоздатьОбъект("Справочник.Клиенты") и перебираем элементы в цикле, сама экранная форма элемента не открывается. Процедура ПриОткрытии(), которая программно заполняет таблицу Ж данными, не выполняется. Соответственно, объект Ж в памяти не существует или равен нулю.Как же правильно получить эти связанные данные программно? В 1С 7.7 связь «один ко многим» реализуется через механизм подчиненных справочников. На форме владельца таблица значений Ж при открытии заполняется элементами этого подчиненного справочника. Чтобы получить количество этих строк в коде отчета, нам необходимо программно обратиться к подчиненному справочнику.
Рассмотрим пример правильного подсчета количества связанных записей:
СпрВладелец = СоздатьОбъект("Справочник.Клиенты");
СпрПодчиненный = СоздатьОбъект("Справочник.Договоры"); // Подчинен справочнику Клиенты
СпрВладелец.ВыбратьЭлементы();
Пока СпрВладелец.ПолучитьЭлемент() = 1 Цикл
Если СпрВладелец.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
// Устанавливаем фильтр по владельцу.
// Метод ТекущийЭлемент() обязателен для позиционирования!
СпрПодчиненный.ИспользоватьВладельца(СпрВладелец.ТекущийЭлемент());
СпрПодчиненный.ВыбратьЭлементы();
КолвоПодчиненных = 0;
Пока СпрПодчиненный.ПолучитьЭлемент() = 1 Цикл
КолвоПодчиненных = КолвоПодчиненных + 1;
КонецЦикла;
Сообщить("Клиент: " + СпрВладелец.Наименование + " | Договоров: " + КолвоПодчиненных);
КонецЦикла;
В процессе обсуждения разработчики упомянули интересный прием проектирования интерфейсов, который позволяет обойти неудобства разработки связки «Владелец -> Таблица значений». Классический подход требует написания огромного объема кода для синхронизации виртуальной таблицы на форме владельца с физическими записями подчиненного справочника.
Суть эмуляции:
Вместо формы элемента справочника-владельца за основу берется форма списка подчиненного справочника:
Этот подход экономит время разработки и значительно повышает стабильность работы конфигурации, сводя к минимуму вероятность рассинхронизации данных при сбоях.