Почему не записывается значение в колонку Таблицы Значений в 1С, хотя в отладчике оно заполнено?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Каждый разработчик на платформе 1С сталкивался с ситуацией, когда код кажется абсолютно верным, отладчик показывает корректные значения переменных, но на выходе в таблице значений или отчете мы получаем пустые поля или нули. Особенно загадочно выглядит ситуация, когда при попытке тестового прибавления числа к переменной (например, СуммаН + 100) в таблицу записывается ровно прибавляемое число (в данном случае 100), как будто исходное значение переменной было равно нулю.

В этой статье мы подробно разберем, почему возникает этот странный эффект, проанализируем неочевидные логические ошибки и рассмотрим проверенные способы их решения.

Загадка «исчезающей» суммы: анализируем симптомы

Рассмотрим классическую ситуацию. В коде выполняется заполнение строки таблицы значений:


НайденнаяСтрока = ТаблицаДанных.Найти(КлючСвязи, "КлючСвязи");
Если НайденнаяСтрока <> Неопределено Тогда
    НайденнаяСтрока.СуммаН = СуммаН;
КонецЕсли;

При пошаговой отладке мы видим, что переменная СуммаН содержит число 21 721.99. Однако после завершения работы алгоритма в таблице значений в колонке СуммаН остается 0.

Если для теста изменить строку кода на:

НайденнаяСтрока.СуммаН = СуммаН + 100;

То в результате в таблице мы увидим значение 100. На первый взгляд это кажется невозможным: если к 21 721.99 прибавить 100, должно получиться 21 821.99. Почему же платформа записывает только 100, игнорируя основную часть суммы?

Давайте разберем по шагам основные технические причины этого поведения.

Причина №1. Последующая свертка таблицы со сторнирующими строками

Это самая частая и математически красивая причина возникновения подобного симптома. Проблема заключается не в самом моменте присвоения значения, а в том, что происходит с таблицей значений после выполнения этого цикла.

Представим, что далее по коду вызывается метод Свернуть():

ТаблицаДанных.Свернуть("КлючСвязи", "СуммаН");

Если в исходной таблице значений перед сверткой присутствовало несколько строк с одинаковым значением колонки КлючСвязи, то при свертке их суммы сложатся.

Представим, что у нас было две строки с одинаковым ключом:

  1. Первая строка (которую мы обрабатывали в цикле): СуммаН = 21 721.99.
  2. Вторая строка (например, корректировочная, сторнирующая или пришедшая из других документов): СуммаН = -21 721.99.

Когда выполняется стандартный алгоритм, эти строки складываются:

21 721.99 + (-21 721.99) = 0

Разработчик видит в итоговой таблице 0 и ошибочно полагает, что сумма не записалась изначально.

Теперь посмотрим, что происходит при нашем тесте с прибавлением 100:

  1. В первой строке мы искусственно завысили значение: СуммаН = 21 721.99 + 100 = 21 821.99.
  2. Вторая строка осталась прежней: СуммаН = -21 721.99.

При последующей свертке эти две строки складываются:

21 821.99 + (-21 721.99) = 100

В результате в итоговой таблице остается ровно 100! Это полностью объясняет поведение системы. Сумма записывалась корректно, но последующая свертка с отрицательным дублем поглотила основное значение.

Решение: Проанализируйте данные в таблице до вызова метода Свернуть(). Проверьте наличие дублирующих строк по группировочным колонкам и наличие отрицательных чисел в ресурсах.

Причина №2. Перезапись одной и той же строки на разных итерациях цикла

Другая распространенная логическая ошибка связана с использованием метода Найти(). Напомним, что метод Найти() объекта ТаблицаЗначений возвращает первую найденную строку, удовлетворяющую условию поиска.

Если ваш ключ поиска не уникален, то в цикле может происходить следующее:


Для Каждого СтрокаИсточника Из ТаблицаИсточников Цикл
    // Метод Найти всегда вернет первую строку с таким Ключом
    НайденнаяСтрока = ТаблицаПолучатель.Найти(СтрокаИсточника.КлючСвязи, "КлючСвязи");
    Если НайденнаяСтрока <> Неопределено Тогда
        // На первой итерации здесь запишется 21 721.99
        // На последующей итерации для этого же ключа СуммаН может быть равна 0
        НайденнаяСтрока.СуммаН = СтрокаИсточника.СуммаН; 
    КонецЕсли;
КонецЦикла;

В этом случае на одной из первых итераций в строку действительно запишется верное число. Но на более поздней итерации для этого же ключа поиска (но другого элемента источника, у которого сумма равна 0) код снова найдет эту же самую первую строку и перезапишет ранее сохраненное значение нулем (или числом 100 в тестовом сценарии).

Решение: Если ключ поиска не уникален, откажитесь от метода Найти(). Используйте метод НайтиСтроки(), который возвращает массив всех подходящих строк, и обрабатывайте их в цикле, либо стройте уникальный ключ для однозначной идентификации строк.


ПараметрыОтбора = Новый Структура("КлючСвязи", СтрокаИсточника.КлючСвязи);
НайденныеСтроки = ТаблицаПолучатель.НайтиСтроки(ПараметрыОтбора);

Для Каждого ТекущаяСтрока Из НайденныеСтроки Цикл
    ТекущаяСтрока.СуммаН = СтрокаИсточника.СуммаН;
КонецЦикла;

Причина №3. Сброс данных через ЗаполнитьЗначенияСвойств

Довольно часто после ручного заполнения отдельных колонок разработчики выполняют групповое копирование свойств из других объектов-источников, не обращая внимания на перекрытие полей. Рассмотрим пример:


НайденнаяСтрока.СуммаН = СуммаН; // Записали верное число

// ... какой-то промежуточный код ...

// ИсточникДокумент содержит свойства, но поле СуммаН в нем пустое или равно 0
ЗаполнитьЗначенияСвойств(НайденнаяСтрока, ИсточникДокумент); 

В данном сценарии метод ЗаполнитьЗначенияСвойств послушно скопирует все совпадающие по именам свойства из объекта ИсточникДокумент в нашу строку таблицы. Если в источнике колонка СуммаН была равна нулю (или вообще отсутствовала, из-за чего инициализировалась значением по умолчанию), ранее записанное число затрется.

Решение: Перенесите вызовы методов заполнения свойств в начало алгоритма обработки строки, а точечные ручные присвоения важных показателей выполняйте в самую последнюю очередь. Либо используйте список исключений в методе заполнения:


// Исключаем затирание колонки СуммаН
ЗаполнитьЗначенияСвойств(НайденнаяСтрока, ИсточникДокумент, , "СуммаН"); 

Причина №4. Ограничения типов и некорректное описание колонок

Иногда проблема кроется в описании типов колонок таблицы значений. Если таблица создается динамически в коде, проверьте, как задан тип для проблемной колонки.

Если колонка была добавлена без явного указания типа или с жестким ограничением длины/точности, платформа может неявно округлять или преобразовывать записываемые типы:


// Ошибка: если колонка создана без типов, она может вести себя непредсказуемо
ТаблицаДанных.Колонки.Добавить("СуммаН"); 

// Правильно: явное указание квалификаторов числа
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2);
ОписаниеТипаЧисло = Новый ОписаниеТипов(МассивТипов, , , КвалификаторыЧисла);

ТаблицаДанных.Колонки.Добавить("СуммаН", ОписаниеТипаЧисло);

Если тип колонки определен неверно (например, ожидает строку, а мы записываем число), то при определенных условиях и приведении типов значение также может сбрасываться или отображаться некорректно.

Рекомендации по поиску ошибок: используем отладчик эффективно

Чтобы быстро локализовать, на каком именно этапе затирается значение в таблице значений, выполните следующие действия в отладчике:

  1. Используйте точки останова с условием. Если у вас большой цикл обработки, настройте точку останова на строке присвоения значения так, чтобы она срабатывала только при обработке интересующего вас ключевого объекта.
  2. Поставьте точку останова после цикла. Сразу после завершения цикла заполнения таблицы посмотрите на её содержимое через «Вычислить выражение» (сочетание клавиш Shift + F9). Если на выходе из цикла все суммы на месте, значит, проблема гарантированно кроется ниже по коду (в свертке, выгрузке, заполнении свойств или выводе на форму).
  3. Проверьте обработчики событий формы. Если таблица значений связана с реквизитом формы и отображается на экране, убедитесь, что в модуле формы не прописаны обработчики событий (например, ПриВыводеСтроки в обычных формах или события при изменении данных), которые могут динамически пересчитывать или очищать выводимые данные.

Соблюдение этих простых правил проектирования алгоритмов и методов отладки позволит вам быстро находить и устранять подобные логические нестыковки в коде 1С.

← На главную