Каждый разработчик на платформе 1С сталкивался с ситуацией, когда код кажется абсолютно верным, отладчик показывает корректные значения переменных, но на выходе в таблице значений или отчете мы получаем пустые поля или нули. Особенно загадочно выглядит ситуация, когда при попытке тестового прибавления числа к переменной (например, СуммаН + 100) в таблицу записывается ровно прибавляемое число (в данном случае 100), как будто исходное значение переменной было равно нулю.
В этой статье мы подробно разберем, почему возникает этот странный эффект, проанализируем неочевидные логические ошибки и рассмотрим проверенные способы их решения.
Рассмотрим классическую ситуацию. В коде выполняется заполнение строки таблицы значений:
НайденнаяСтрока = ТаблицаДанных.Найти(КлючСвязи, "КлючСвязи");
Если НайденнаяСтрока <> Неопределено Тогда
НайденнаяСтрока.СуммаН = СуммаН;
КонецЕсли;
При пошаговой отладке мы видим, что переменная СуммаН содержит число 21 721.99. Однако после завершения работы алгоритма в таблице значений в колонке СуммаН остается 0.
Если для теста изменить строку кода на:
НайденнаяСтрока.СуммаН = СуммаН + 100;
То в результате в таблице мы увидим значение 100. На первый взгляд это кажется невозможным: если к 21 721.99 прибавить 100, должно получиться 21 821.99. Почему же платформа записывает только 100, игнорируя основную часть суммы?
Давайте разберем по шагам основные технические причины этого поведения.
Это самая частая и математически красивая причина возникновения подобного симптома. Проблема заключается не в самом моменте присвоения значения, а в том, что происходит с таблицей значений после выполнения этого цикла.
Представим, что далее по коду вызывается метод Свернуть():
ТаблицаДанных.Свернуть("КлючСвязи", "СуммаН");
Если в исходной таблице значений перед сверткой присутствовало несколько строк с одинаковым значением колонки КлючСвязи, то при свертке их суммы сложатся.
Представим, что у нас было две строки с одинаковым ключом:
СуммаН = 21 721.99.СуммаН = -21 721.99.Когда выполняется стандартный алгоритм, эти строки складываются:
21 721.99 + (-21 721.99) = 0
Разработчик видит в итоговой таблице 0 и ошибочно полагает, что сумма не записалась изначально.
Теперь посмотрим, что происходит при нашем тесте с прибавлением 100:
СуммаН = 21 721.99 + 100 = 21 821.99.СуммаН = -21 721.99.При последующей свертке эти две строки складываются:
21 821.99 + (-21 721.99) = 100
В результате в итоговой таблице остается ровно 100! Это полностью объясняет поведение системы. Сумма записывалась корректно, но последующая свертка с отрицательным дублем поглотила основное значение.
Решение: Проанализируйте данные в таблице до вызова метода Свернуть(). Проверьте наличие дублирующих строк по группировочным колонкам и наличие отрицательных чисел в ресурсах.
Другая распространенная логическая ошибка связана с использованием метода Найти(). Напомним, что метод Найти() объекта ТаблицаЗначений возвращает первую найденную строку, удовлетворяющую условию поиска.
Если ваш ключ поиска не уникален, то в цикле может происходить следующее:
Для Каждого СтрокаИсточника Из ТаблицаИсточников Цикл
// Метод Найти всегда вернет первую строку с таким Ключом
НайденнаяСтрока = ТаблицаПолучатель.Найти(СтрокаИсточника.КлючСвязи, "КлючСвязи");
Если НайденнаяСтрока <> Неопределено Тогда
// На первой итерации здесь запишется 21 721.99
// На последующей итерации для этого же ключа СуммаН может быть равна 0
НайденнаяСтрока.СуммаН = СтрокаИсточника.СуммаН;
КонецЕсли;
КонецЦикла;
В этом случае на одной из первых итераций в строку действительно запишется верное число. Но на более поздней итерации для этого же ключа поиска (но другого элемента источника, у которого сумма равна 0) код снова найдет эту же самую первую строку и перезапишет ранее сохраненное значение нулем (или числом 100 в тестовом сценарии).
Решение: Если ключ поиска не уникален, откажитесь от метода Найти(). Используйте метод НайтиСтроки(), который возвращает массив всех подходящих строк, и обрабатывайте их в цикле, либо стройте уникальный ключ для однозначной идентификации строк.
ПараметрыОтбора = Новый Структура("КлючСвязи", СтрокаИсточника.КлючСвязи);
НайденныеСтроки = ТаблицаПолучатель.НайтиСтроки(ПараметрыОтбора);
Для Каждого ТекущаяСтрока Из НайденныеСтроки Цикл
ТекущаяСтрока.СуммаН = СтрокаИсточника.СуммаН;
КонецЦикла;
Довольно часто после ручного заполнения отдельных колонок разработчики выполняют групповое копирование свойств из других объектов-источников, не обращая внимания на перекрытие полей. Рассмотрим пример:
НайденнаяСтрока.СуммаН = СуммаН; // Записали верное число
// ... какой-то промежуточный код ...
// ИсточникДокумент содержит свойства, но поле СуммаН в нем пустое или равно 0
ЗаполнитьЗначенияСвойств(НайденнаяСтрока, ИсточникДокумент);
В данном сценарии метод ЗаполнитьЗначенияСвойств послушно скопирует все совпадающие по именам свойства из объекта ИсточникДокумент в нашу строку таблицы. Если в источнике колонка СуммаН была равна нулю (или вообще отсутствовала, из-за чего инициализировалась значением по умолчанию), ранее записанное число затрется.
Решение: Перенесите вызовы методов заполнения свойств в начало алгоритма обработки строки, а точечные ручные присвоения важных показателей выполняйте в самую последнюю очередь. Либо используйте список исключений в методе заполнения:
// Исключаем затирание колонки СуммаН
ЗаполнитьЗначенияСвойств(НайденнаяСтрока, ИсточникДокумент, , "СуммаН");
Иногда проблема кроется в описании типов колонок таблицы значений. Если таблица создается динамически в коде, проверьте, как задан тип для проблемной колонки.
Если колонка была добавлена без явного указания типа или с жестким ограничением длины/точности, платформа может неявно округлять или преобразовывать записываемые типы:
// Ошибка: если колонка создана без типов, она может вести себя непредсказуемо
ТаблицаДанных.Колонки.Добавить("СуммаН");
// Правильно: явное указание квалификаторов числа
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2);
ОписаниеТипаЧисло = Новый ОписаниеТипов(МассивТипов, , , КвалификаторыЧисла);
ТаблицаДанных.Колонки.Добавить("СуммаН", ОписаниеТипаЧисло);
Если тип колонки определен неверно (например, ожидает строку, а мы записываем число), то при определенных условиях и приведении типов значение также может сбрасываться или отображаться некорректно.
Чтобы быстро локализовать, на каком именно этапе затирается значение в таблице значений, выполните следующие действия в отладчике:
Shift + F9). Если на выходе из цикла все суммы на месте, значит, проблема гарантированно кроется ниже по коду (в свертке, выгрузке, заполнении свойств или выводе на форму).ПриВыводеСтроки в обычных формах или события при изменении данных), которые могут динамически пересчитывать или очищать выводимые данные.Соблюдение этих простых правил проектирования алгоритмов и методов отладки позволит вам быстро находить и устранять подобные логические нестыковки в коде 1С.