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