В процессе разработки в 1С часто возникает задача отследить изменения в табличной части (ТЧ) документа. Обычное сравнение по номеру строки неэффективно: если пользователь удалит четвертую строку из десяти, все последующие строки сместятся, и стандартные индексы перестанут соответствовать первоначальным данным. Мы разберем, как правильно идентифицировать строки и какие программные методы лучше всего подходят для поиска отличий "до" и "после" записи.
Разберем типичную ситуацию: в табличной части находятся обычные товары. Если в ТЧ нет уникального реквизита (например, какого-то внутреннего ключа), то система воспринимает строки просто как набор данных. При перемещении строк или их пересоздании по номеру строки понять, что именно изменилось, невозможно.
Для решения этой задачи в Управляемых Формах (УФ) предусмотрен механизм идентификаторов. Каждая строка коллекции ДанныеФормыКоллекция имеет свой внутренний идентификатор. Проанализируем, как с ним работать:
ПолучитьИдентификатор().Рассмотрим пример кода для обхода строк с получением их идентификаторов:
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
Идентификатор = СтрокаТЧ.ПолучитьИдентификатор();
// Сохраняем идентификатор вместе с данными для последующего сравнения
КонецЦикла;
Важное ограничение: идентификаторы управляемой формы существуют только "в памяти" текущего сеанса формы. Они не сохраняются в базе данных. Если вы закроете форму и откроете её снова, идентификаторы будут назначены заново. Поэтому этот метод подходит для сравнения данных в цикле "открыл — изменил — нажал Записать".
Если нам нужно сравнить текущее состояние объекта с тем, что уже записано в базе данных (ссылкой), наиболее профессиональным и производительным способом будет использование запроса с полным внешним соединением. Проанализируем алгоритм этого метода:
Сначала мы выгружаем текущую табличную часть объекта (которая еще не записана в БД) во временную таблицу. Затем в этом же запросе выбираем данные из таблицы этой же ТЧ, но уже по ссылке на документ.
Рассмотрим логику условий в запросе:
Посмотрим на пример структуры такого запроса:
"ВЫБРАТЬ * ПОМЕСТИТЬ НовыеДанные ИЗ &ТЗ_Новые КАК ТЗ;
ВЫБРАТЬ
ЕСТЬNULL(Старые.Номенклатура, Новые.Номенклатура) КАК Номенклатура,
ВЫБОР
КОГДА Старые.Номенклатура ЕСТЬ NULL ТОГДА ""Добавлена""
КОГДА Новые.Номенклатура ЕСТЬ NULL ТОГДА ""Удалена""
ИНАЧЕ ""Изменена""
КОНЕЦ КАК СтатусИзменения
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Старые
ПОЛНОЕ СОЕДИНЕНИЕ НовыеДанные КАК Новые
ПО Старые.Номенклатура = Новые.Номенклатура И Старые.НомерСтроки = Новые.НомерСтроки
ГДЕ Ссылка = &Ссылка"
Выясним причину популярности метода сериализации. Если нам не нужно детально знать, какая именно ячейка изменилась, а достаточно зафиксировать сам факт отличия ТЧ (например, для логирования), можно использовать "снимки" данных.
Рассмотрим последовательность действий:
Использование ЗаписатьJSON в современных версиях платформы 8.3 работает быстрее, чем старые методы ЗначениеВСтрокуВнутр. Это позволяет эффективно хранить состояние ТЧ во временном хранилище или в скрытом реквизите формы для последующего сопоставления.
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Объект.Товары.Выгрузить());
СтрокаСостояния = ЗаписьJSON.Закрыть();
Для максимально точного отслеживания строк, которое не зависит от контекста формы или сеанса, опытные разработчики применяют метод "Ключа строки". Разберем его суть:
В метаданные табличной части добавляется реквизит КлючСтроки с типом УникальныйИдентификатор или Число. При добавлении новой строки (событие ПриУстановкеНовогоНомера или ПередЗаписью) мы программно генерируем уникальное значение для этого поля и записываем его в базу.
Преимущества этого подхода:
КлючСтроки.Проанализируем ситуацию, когда табличная часть очень большая (тысячи строк). Посимвольное сравнение каждой колонки может быть медленным. В этом случае удобно использовать хеширование.
Для каждой строки формируется текстовая строка из всех значимых полей (Номенклатура + Количество + Цена + Склад), и от этого текста вычисляется короткий хеш-код. При проверке изменений вы сравниваете только эти коды. Если хеш совпал — строка гарантированно не менялась. Если не совпал — мы анализируем строку подробнее.
Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), рекомендуем обратить внимание на общие модули для работы с объектами. В БСП часто реализованы вспомогательные функции, которые позволяют сравнивать коллекции значений или проверять модифицированность конкретных реквизитов, избегая ошибок с пустыми ссылками или неопределенными значениями.
Также помните про стандартное свойство Модифицированность(). Хотя оно и показывает, что объект изменился, оно часто срабатывает даже при перезаписи тех же самых данных. Поэтому для детального анализа ТЧ всегда используйте один из описанных выше методов: идентификаторы формы для оперативной работы или сравнение с данными базы через запрос для финальной фиксации изменений.