В процессе разработки или кастомизации типовых конфигураций, таких как 1С:Бухгалтерия предприятия 3.0, программисты часто сталкиваются с задачей сортировки табличной части документа. Казалось бы, задача тривиальная: достаточно вызвать метод Сортировать(). Однако, если мы попытаемся отсортировать таблицу товаров по колонке Артикул, система может выдать ошибку «Колонка не найдена». Рассмотрим подробно, почему это происходит и как правильно решить эту задачу несколькими способами.
Проанализируем структуру типичной табличной части Товары. В большинстве типовых решений колонка Артикул (который может быть заполнен, например, при создании номенклатуры по данным контрагента) не является физическим реквизитом самой табличной части. Если мы заглянем в конфигуратор и посмотрим на свойства элемента формы, то увидим, что ПутьКДанным для этой колонки выглядит как Объект.Товары.Номенклатура.Артикул.
Это означает, что данные в колонке отображаются «через точку» от справочника Номенклатура (где также могут храниться универсальные аналоги номенклатуры). Для платформы 1С метод Сортировать() работает исключительно с физическими колонками, которые присутствуют в коллекции (в реквизитах табличной части). Поскольку реквизита Артикул в таблице нет, метод выдает ошибку. Чтобы решить эту задачу, нам необходимо временно «материализовать» эти данные для выполнения операции сортировки.
Самый надежный способ, который подходит для внешних подключаемых обработок и расширений, — это использование временной ТаблицыЗначений. Рассмотрим алгоритм действий:
ТаблицаЗначений.Артикул.Разберем программную реализацию этого алгоритма. Обратите внимание, что работа с ТаблицейЗначений возможна только на стороне сервера.
&НаСервере
Процедура СортироватьТЧПоАртикулуНаСервере()
// 1. Выгружаем ТЧ в таблицу значений
ТЗ = Объект.Товары.Выгрузить();
// 2. Добавляем временную колонку для сортировки
ТЗ.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(25)));
// 3. Заполняем колонку значениями артикула
Для Каждого СтрокаТЗ Из ТЗ Цикл
// Обращаемся к реквизиту номенклатуры
СтрокаТЗ.Артикул = СтрокаТЗ.Номенклатура.Артикул;
КонецЦикла;
// 4. Сортируем по возрастанию
ТЗ.Сортировать("Артикул Возр");
// 5. Удаляем временную колонку (необязательно, но желательно для чистоты данных)
ТЗ.Колонки.Удалить("Артикул");
// 6. Загружаем данные обратно в объект
Объект.Товары.Очистить();
Объект.Товары.Загрузить(ТЗ);
КонецПроцедуры
Проанализируем вышеописанный код. Если в табличной части документа содержится большое количество строк (например, несколько сотен или тысяч), обращение к реквизиту Артикул через точку в цикле Для Каждого может существенно замедлить работу. Это происходит из-за так называемой «проблемы N+1 запроса», когда система вынуждена обращаться к базе данных за артикулом для каждой отдельной строки.
Посмотрим на пример более эффективного решения с использованием объекта Запрос. Мы получим все артикулы одним махом.
&НаСервере
Процедура ОптимизированнаяСортировкаНаСервере()
ТЗ = Объект.Товары.Выгрузить();
// Используем запрос для быстрого получения соответствия Номенклатура -> Артикул
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Номенклатура.Артикул КАК Артикул
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ТЗ_Товары КАК Товары
|;
|
|ВЫБРАТЬ
| ВТ_Данные.Номенклатура,
| ВТ_Данные.Артикул
|ИЗ
| ВТ_Данные КАК ВТ_Данные";
Запрос.УстановитьПараметр("ТЗ_Товары", ТЗ);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Добавляем колонку в исходную ТЗ и заполняем её через поиск в результате запроса
ТЗ.Колонки.Добавить("Артикул");
Для Каждого СтрокаТЗ Из ТЗ Цикл
СтрокаПоиска = РезультатЗапроса.Найти(СтрокаТЗ.Номенклатура, "Номенклатура");
Если СтрокаПоиска <> Неопределено Тогда
СтрокаТЗ.Артикул = СтрокаПоиска.Артикул;
КонецЕсли;
КонецЦикла;
ТЗ.Сортировать("Артикул");
Объект.Товары.Загрузить(ТЗ);
КонецПроцедуры
Если вы разрабатываете дополнительную обработку табличной части через механизм Библиотеки стандартных подсистем (БСП), помните, что вы работаете с контекстом формы документа. Рассмотрим важные моменты:
ПараметрыВыполнения.ПараметрыВыполнения.ЭтаФорма.Объект.Объект на сервере в рамках обработки, не забудьте убедиться, что данные синхронизированы с формой. В управляемых формах часто используется метод КопироватьДанныеФормы() для передачи изменений из прикладного объекта обратно в данные формы.Проанализируем пример вызова из модуля обработки:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
// Получаем форму и объект документа
ФормаДокумента = ПараметрыВыполнения.ЭтаФорма;
ДокументОбъект = ФормаДокумента.Объект;
// Выполняем сортировку (логика как в Решении 1)
// ... (код сортировки) ...
// Важно: так как мы работаем с формой, изменения должны отразиться на экране
// В некоторых случаях может потребоваться явное уведомление формы
// КопироватьДанныеФормы(ДокументОбъект, ФормаДокумента.Объект);
КонецПроцедуры
Если требование сортировки по артикулу является постоянным для пользователей, рассмотрите вариант с использованием расширения конфигурации. Это позволит сделать колонку Артикул реальным реквизитом табличной части Товары.
Преимущества этого метода:
Для реализации этого метода добавьте в расширение табличную часть документа, создайте в ней новый реквизит Артикул и настройте его автоматическое заполнение в процедуре ПриИзменении для номенклатуры. Таким образом, данные будут всегда под рукой и готовы к штатной сортировке средствами 1С:Предприятие.
Важное замечание по типам данных: Помните, что Артикул — это строка. Сортировка строковых данных в 1С происходит посимвольно. Если ваши артикулы состоят из цифр разной длины (например, "1", "2", "10"), то при сортировке по возрастанию "10" может оказаться между "1" и "2". Чтобы избежать этого, артикулы должны иметь фиксированную длину с ведущими нулями или приводиться к числовому типу в промежуточной ТаблицеЗначений.