При разработке сложных алгоритмов корректировки движений в 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда метод Модифицированность() ведет себя не так, как ожидается. Особенно это заметно при работе с наборами записей регистров бухгалтерии. Давайте подробно разберем, почему программное изменение ресурсов и реквизитов внутри набора не «взводит» флаг модифицированности, и как с этим правильно работать.
Рассмотрим стандартную ситуацию, которую описывает автор темы. Мы создаем набор записей, читаем его по определенному регистратору и пытаемся изменить данные в цикле. Код выглядит примерно так:
пПроводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
пПроводки.Отбор.Регистратор.Установить(ДокументСсылка);
пПроводки.Прочитать();
Для Каждого пПроводка Из пПроводки Цикл
// Предположим, здесь есть логика проверки
пПроводка.СуммаНУДт = 0;
пПроводка.СуммаПРДт = 0;
// ... изменение других ресурсов
КонецЦикла;
Если пПроводки.Модифицированность() Тогда
пПроводки.Записать();
КонецЕсли;
Несмотря на то что данные внутри коллекции пПроводки действительно изменились (в чем можно убедиться в отладчике), метод Модифицированность() упорно возвращает значение Ложь. Проанализируем причину такого поведения платформы.
В системе 1С:Предприятие метод Модифицированность() имеет разную механику работы для «Объектов» (таких как СправочникОбъект, ДокументОбъект) и для «Наборов записей». Для ссылочных объектов изменение любого реквизита сразу меняет состояние объекта на «измененный». Однако для наборов записей этот механизм тесно связан с интерактивной работой в формах.
Важный технический нюанс: Платформа гарантированно фиксирует модифицированность набора записей только в том случае, если изменения происходят в табличном поле формы пользователем или если в коде вызываются методы, меняющие структуру коллекции (Добавить(), Удалить(), Вставить()). Простое присваивание новых значений полям уже существующих строк в памяти часто не регистрируется внутренним механизмом отслеживания изменений как повод для взведения флага программного объекта.
Поскольку полагаться на стандартный метод при программном обходе записей нельзя, самым надежным и распространенным решением является введение собственной переменной-флага. Рассмотрим, как это реализовать правильно, чтобы избежать лишних записей в базу данных (которые могут замедлять работу системы и вызывать лишние блокировки).
Выясним, как интегрировать свой флаг в алгоритм:
пПроводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
пПроводки.Отбор.Регистратор.Установить(ДокументСсылка);
пПроводки.Прочитать();
ЛокальнаяМодифицированность = Ложь;
Для Каждого пПроводка Из пПроводки Цикл
// Проверяем, нужно ли реально менять значение, чтобы не взводить флаг зря
Если пПроводка.СуммаНУДт <> 0 Тогда
пПроводка.СуммаНУДт = 0;
ЛокальнаяМодифицированность = Истина;
КонецЕсли;
// Аналогично для других ресурсов
Если пПроводка.СуммаПРДт <> 0 Тогда
пПроводка.СуммаПРДт = 0;
ЛокальнаяМодифицированность = Истина;
КонецЕсли;
КонецЦикла;
// Используем свой флаг вместо системного метода
Если ЛокальнаяМодифицированность Тогда
пПроводки.Записать();
КонецЕсли;
Этот подход является наиболее «чистым» с точки зрения производительности. Мы вызываем Записать() только тогда, когда в данных действительно произошли изменения.
В некоторых случаях, если алгоритм гарантирует, что данные будут изменены, или если объем записей невелик, разработчики предпочитают отказываться от проверки вовсе. Если мы вызвали метод Прочитать(), изменили данные и уверены, что их нужно сохранить, можно сразу вызывать метод Записать().
Проанализируем этот вариант:
Стоит отметить, что поведение метода Модифицированность() для РегистрНакопленияНаборЗаписей или РегистрСведенийНаборЗаписей аналогично регистру бухгалтерии. Ошибка многих разработчиков заключается в ожидании, что НаборЗаписей — это такой же «Объект» в памяти, как ДокументОбъект. На самом деле это специализированная коллекция, оптимизированная для массовой работы с данными, и ее состояние отслеживается платформой иначе.
Разберем еще один важный момент: если вы используете НаборЗаписей в форме документа (например, вывели движения на отдельную закладку), то при изменении данных в коде формы флаг модифицированности самой Формы может быть установлен (через свойство ЭтотОбъект.Модифицированность), но системный флаг самого программного объекта набора все равно может остаться в значении Ложь до момента интерактивного действия пользователя в строке.
Подводя итог нашему разбору, выделим основные правила работы с признаком изменения записей:
Модифицированность() для программно созданных наборов записей вне контекста форм, если вы только меняете значения полей в существующих строках.Добавить()) или удаление строк в наборе обычно корректно взводит системную модифицированность, но для надежности в сложных алгоритмах лучше всегда использовать явный флаг (Булево).Записать() полностью замещает существующие в базе записи по данному регистратору (или набору измерений для независимых регистров) теми, что находятся в памяти набора.Соблюдение этих простых правил поможет избежать трудноуловимых ошибок, когда данные в базе «почему-то не обновились», хотя код отработал без ошибок, но просто не прошел внутрь условия Если Модифицированность() Тогда.