Разработка и Конфигурация · 12 мин
Как изменить строку таблицы значений в 1С
Как изменить строку таблицы значений в 1С: обращение по индексу, поиск через Найти и НайтиСтроки, обход в цикле, типичные ошибки и примеры кода на встроенном языке.
Таблица значений в 1С — это объект встроенного языка, который хранится только в оперативной памяти и не привязан к базе данных. Поэтому изменить строку в ней нельзя «запросом» или записью в регистр: все правки выполняются программно через коллекцию строк. Разработчик получает нужную строку как объект СтрокаТаблицыЗначений и присваивает новые значения её полям — изменения применяются сразу, без дополнительного вызова «Записать».
Типовая задача звучит так: есть таблица с колонками «Номенклатура», «Количество», «Цена», и нужно скорректировать цену у конкретной позиции или пересчитать суммы во всех строках. В зависимости от того, известен ли индекс строки, задано ли условие поиска или требуется обработать всю таблицу, выбирается один из четырёх подходов: обращение по индексу, метод Найти(), метод НайтиСтроки() или обход в цикле.
Ниже разобраны все способы с рабочим кодом, условиями выбора между ними, проверкой результата и разбором ошибок, которые чаще всего приводят к падению кода или молчаливой потере изменений.
Как устроена таблица значений и почему строка меняется напрямую
Объект ТаблицаЗначений состоит из коллекции колонок (Колонки) и коллекции строк. Каждая строка — самостоятельный объект типа СтрокаТаблицыЗначений, доступ к её полям идёт через точку по имени колонки: Строка.Цена = 150;. Поскольку переменная содержит ссылку на объект, а не его копию, присвоение значения полю немедленно меняет данные в самой таблице.
Из этого следуют два практических вывода. Во-первых, не существует метода «ОбновитьСтроку» или «ЗаписатьСтроку» — они не нужны. Во-вторых, ошибка возникает не при записи, а на этапе получения строки: если строка не найдена или индекс указан неверно, код обратится к Неопределено или выйдет за границы коллекции и завершится исключением.
Изменение строки по индексу
Самый быстрый способ — обратиться к строке по её позиции. Индексация начинается с нуля, поэтому первая строка — ТЗ[0], а последняя — ТЗ[ТЗ.Количество() - 1]. Альтернативный синтаксис — метод Получить(Индекс), он эквивалентен квадратным скобкам.
// Изменим цену в первой строке
Если ТЗ.Количество() > 0 Тогда
ТЗ[0].Цена = 250;
ТЗ[0].Сумма = ТЗ[0].Количество * ТЗ[0].Цена;
КонецЕсли;
Способ уместен, когда позиция строки известна заранее: например, обработчик изменения табличной части формы передаёт индекс текущей строки, либо строка только что добавлена методом Добавить() и является последней. Во всех остальных случаях опираться на «жёсткий» индекс опасно: после сортировки, удаления строк или загрузки данных порядок меняется, и код начнёт править не ту строку.
Изменение строки, найденной по значению: метод Найти
Метод Найти(Значение, Колонки) возвращает первую строку, где указанные колонки равны искомому значению, либо Неопределено, если совпадений нет. Это основной способ точечной правки, когда строка идентифицируется бизнес-ключом — кодом номенклатуры, артикулом, ссылкой.
Строка = ТЗ.Найти(ИскомаяНоменклатура, "Номенклатура");
Если Строка <> Неопределено Тогда
Строка.Цена = НоваяЦена;
Строка.Сумма = Строка.Количество * НоваяЦена;
Иначе
// строки нет — добавляем или фиксируем в журнале
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = ИскомаяНоменклатура;
НоваяСтрока.Цена = НоваяЦена;
КонецЕсли;
Обратите внимание на ветку Иначе: пропуск проверки на Неопределено — самая частая причина ошибки «Поле объекта не обнаружено». Правильная реакция на отсутствие строки зависит от логики задачи: иногда нужно добавить новую строку, иногда — записать предупреждение, иногда — просто ничего не делать.
Второй параметр метода ограничивает поиск перечисленными колонками. Если его опустить, поиск пойдёт по всем колонкам, что почти никогда не нужно и замедляет выполнение на больших таблицах.
Изменение нескольких строк: НайтиСтроки и отбор по структуре
Когда условию соответствует несколько строк — например, нужно обнулить скидку у всех позиций одной группы товаров — используется НайтиСтроки(ПараметрыОтбора). Метод принимает структуру, где ключи — имена колонок, а значения — искомые значения, и возвращает массив строк. Если совпадений нет, массив будет пустым, а не Неопределено, поэтому проверка делается через Количество() или просто обходом цикла.
Отбор = Новый Структура;
Отбор.Вставить("ГруппаТоваров", "Материалы");
Отбор.Вставить("Отгружено", Ложь);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
Строка.Скидка = 0;
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
Важно понимать ограничение: отбор в НайтиСтроки работает только на точное равенство. Условия вида «цена больше 1000» или «наименование содержит подстроку» через структуру не выразить — для них нужен обход таблицы в цикле с проверкой внутри.
Сравнение вариантов
Подходит, когда позиция строки известна точно: текущая строка формы, только что добавленная строка. Не подходит после сортировки или удаления строк — порядок меняется.
Подходит для точечной правки одной строки по ключу. Возвращает только первое совпадение и Неопределено при отсутствии — требуется проверка.
Подходит для массовой правки строк по условию равенства в нескольких колонках. Не поддерживает сравнения «больше/меньше» и поиск по подстроке.
Универсальный вариант для сложных условий и пересчёта всех строк. Самый медленный на больших таблицах, требует аккуратности при удалении строк внутри цикла.
Обход таблицы в цикле и пересчёт всех строк
Цикл Для Каждого — универсальный инструмент, когда менять нужно все строки или условие не сводится к равенству. Внутри цикла переменная содержит ссылку на реальную строку таблицы, поэтому присвоения работают напрямую.
Для Каждого Строка Из ТЗ Цикл
Если Строка.Количество > 10 Тогда
Строка.Скидка = 5;
КонецЕсли;
Строка.Сумма = Строка.Количество * Строка.Цена
* (100 - Строка.Скидка) / 100;
КонецЦикла;
Отдельный сценарий — изменение строк с одновременным удалением части из них. Обход коллекции «вперёд» при удалении пропускает элементы: после удаления строки индексы сдвигаются, и следующая строка оказывается пропущенной. Безопасный приём — идти с конца таблицы по индексу:
Для Инд = 1 По ТЗ.Количество() Цикл
Строка = ТЗ[ТЗ.Количество() - Инд];
Если Строка.Количество = 0 Тогда
ТЗ.Удалить(Строка);
Иначе
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЕсли;
КонецЦикла;
Особые случаи: форма, дерево значений и типизированные колонки
Строка таблицы на управляемой форме
Если таблица значений является реквизитом управляемой формы, текущая строка доступна через Элементы.ИмяТаблицы.ТекущиеДанные. Это объект ДанныеФормыСтруктура, но поля меняются так же — через присвоение. Через ТекущаяСтрока элемента формы можно получить идентификатор строки и затем саму строку методом НайтиПоИдентификатору() коллекции ДанныеФормыКоллекция.
Строки дерева значений
В дереве значений поиск методами Найти и НайтиСтроки по умолчанию идёт только по строкам верхнего уровня. Чтобы изменить строку внутри ветки, либо обходите иерархию рекурсивно через Строки каждого уровня, либо используйте параметр поиска с учётом иерархии там, где он предусмотрен. Строка дерева дополнительно имеет свойства Родитель и Строки, через которые удобно подниматься и спускаться по веткам.
Тип значения при присвоении
Если колонка создана с описанием типов, присваиваемое значение приводится к допустимому типу. Присвоение строки в числовую колонку не вызовет ошибки немедленно, но может дать 0 или непредсказуемое значение при последующих вычислениях. Перед массовой загрузкой данных из внешних источников (Excel, CSV) проверяйте типы колонок через ТЗ.Колонки.Найти("Цена").ТипЗначения и явно преобразуйте значения функциями Число(), Дата(), Строка().
Проверка результата и отладка
После изменения строки убедитесь, что правка действительно применилась к таблице, а не к «потерянной» переменной. Самый надёжный способ — точка останова в конфигураторе и просмотр таблицы через «Вычислить выражение»: в отладчике таблица значений отображается в виде сетки, где видно новые значения колонок.
Для программной проверки полезно повторно найти строку и сравнить значение поля с ожидаемым, а также контролировать ТЗ.Количество() до и после операции — не должно неожиданно измениться. При массовых правках имеет смысл считать число фактически изменённых строк и выводить его в журнал регистрации или сообщение: ноль изменённых строк — явный признак того, что условие отбора не сработало.
Как проверить результат
Повторный Найти() возвращает строку с новым значением
Значение осталось прежним — правили копию или другую строку
Совпадает с ожиданием после правок и удалений
Строк стало меньше или больше — сработало лишнее удаление или добавление
Счётчик равен числу строк, удовлетворяющих условию
Счётчик равен нулю — условие отбора или сравнение значений некорректно
Значение соответствует описанию типов колонки
В числовой колонке строка или Неопределено — расчёты дадут неверный итог
Частые вопросы
Как изменить значение в таблице значений, если известна только часть наименования?
Методы Найти и НайтиСтроки работают только на точное совпадение, поэтому для поиска по подстроке нужен обход в цикле с функцией СтрНайти(): если СтрНайти(Строка.Наименование, Подстрока) > 0, строка подходит и её поля можно менять. Учитывайте регистр символов — при необходимости приводите обе строки функцией ВРег() или НРег().
Почему после присвоения Строка.Цена = 100 значение в таблице не изменилось?
Чаще всего переменная содержит не строку исходной таблицы, а строку её копии или выборки. Проверьте, откуда получена строка: если таблица передана в функцию по значению (параметр со словом Знач), правки уйдут в локальную копию. Передавайте таблицу по ссылке или возвращайте изменённую таблицу из функции.
Можно ли переименовать колонку или изменить порядок полей у существующей строки?
Напрямую переименовать колонку нельзя: коллекция колонок поддерживает добавление, удаление и сдвиг методом Сдвинуть(), но не переименование. Обходной путь — добавить колонку с новым именем, перенести значения в цикле по всем строкам и удалить старую колонку.
Как изменить сразу несколько полей строки одним действием?
Специального метода пакетного присвоения нет — поля заполняются последовательными присвоениями. Сократить код помогает метод ЗаполнитьЗначения(Строка, Источник, "Цена,Сумма"), если значения уже собраны в структуру или другую строку с совпадающими именами полей.
Что быстрее на больших таблицах: Найти, НайтиСтроки или цикл?
Разовый Найти и обход циклом сопоставимы по скорости, поскольку оба идут последовательным перебором. Если поиск по одному и тому же ключу выполняется многократно, эффективнее построить индекс методом ТЗ.Индексы.Добавить("Номенклатура") — тогда Найти и НайтиСтроки будут использовать индекс и отработают заметно быстрее.
Как изменить строку табличной части документа — так же, как таблицу значений?
Принцип тот же: получить строку по индексу или в цикле и присвоить значения полям. Разница в том, что табличная часть принадлежит объекту документа, поэтому после правок объект нужно записать методом Записать(), иначе изменения не попадут в базу данных.
Что важно запомнить
Строка таблицы значений меняется прямым присвоением полей после получения объекта строки — по индексу, через Найти, НайтиСтроки или в цикле. Всегда проверяйте результат поиска на Неопределено, не удаляйте строки в прямом цикле и помните: таблица значений хранится в памяти, для сохранения данных её нужно отдельно перенести в объект базы.