При разработке систем аудита, синхронизации данных или детального версионирования программисты 1С часто сталкиваются с проблемой идентификации конкретной строки табличной части. Стандартный реквизит НомерСтроки крайне ненадежен: при удалении любой вышестоящей строки или при обычной сортировке номера пересчитываются. В результате в базе данных строка с номером 2 может стать строкой номер 1, и простое сравнение по индексу покажет ложное изменение данных.
В этой статье мы подробно разберем, как обойти это ограничение платформы, рассмотрим встроенные механизмы и научимся внедрять собственные системы идентификации строк.
Проанализируем ситуацию на уровне базы данных. В системе 1С:Предприятие при записи объекта (документа или справочника) табличная часть в SQL-таблице полностью перезаписывается. Платформа удаляет все записи, относящиеся к данному объекту, и записывает их заново. Техническое поле _KeyField, которое существует в SQL-таблицах табличных частей, является системным идентификатором записи (RowID), но оно генерируется заново при каждой перезаписи. Поэтому полагаться на него для отслеживания изменений между двумя версиями документа невозможно. Выясним, какие инструменты у нас есть в арсенале для решения этой задачи.
Начиная с версии 8.3.11, в платформу встроен мощный механизм ИсторияДанных. Разберем по шагам, почему это зачастую лучший выбор:
ИсторияДанных.ВыбратьВерсии() и сравнить их.Однако, если ваша задача — передавать изменения во внешнюю систему в режиме реального времени или работать в сильно кастомизированной старой конфигурации, этого может быть недостаточно. Перейдем к более гибким методам.
Это самый надежный способ «жесткой» привязки. Идея заключается в добавлении в каждую табличную часть реквизита (например, с именем ИдентификаторСтроки) с типом УникальныйИдентификатор или Строка(36).
Рассмотрим, как автоматизировать заполнение этого реквизита, чтобы не заставлять пользователя или других разработчиков делать это вручную. Нам понадобится подписка на событие ПередЗаписью для документов. Проанализируем пример кода для такой подписки:
Процедура ПередЗаписьюДокументаДляАудита(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
МетаданныеОбъекта = Источник.Метаданные();
// Перебираем все табличные части документа
Для Каждого ТЧМетаданные Из МетаданныеОбъекта.ТабличныеЧасти Цикл
ИмяТЧ = ТЧМетаданные.Имя;
// Проверяем наличие нашего служебного реквизита
Если ТЧМетаданные.Реквизиты.Найти("ИдентификаторСтроки") = Неопределено Тогда
Продолжить;
КонецЕсли;
// Заполняем пустые идентификаторы
Для Каждого СтрокаТЧ Из Источник[ИмяТЧ] Цикл
Если СтрокаТЧ.ИдентификаторСтроки.Пустая() Тогда
СтрокаТЧ.ИдентификаторСтроки = Новый УникальныйИдентификатор();
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Если вы добавляете GUID, обязательно сделайте его скрытым от пользователя на формах, чтобы исключить случайное редактирование или копирование вместе с данными строки.
В современных конфигурациях на базе БСП (ERP, УТ 11, КА) часто используется механизм КлючСвязи. Разберем, как он работает. Обычно это числовой реквизит, который уникален только в пределах конкретного документа. Он используется для связи строк разных табличных частей (например, Товары и ШтрихкодыУпаковок).
Если вам нужно отслеживать изменения только внутри одного сеанса работы или одной базы, Число эффективнее, чем GUID, так как оно занимает меньше места и быстрее индексируется. Но для распределенных систем и выгрузок во внешние БД лучше использовать именно УникальныйИдентификатор.
Если вы не имеете возможности менять структуру таблиц (например, в закрытой системе или если табличных частей слишком много), рассмотрим вариант с вычислением хэша. Мы можем создать «отпечаток» строки, который будет зависеть от её содержимого.
Посмотрим на алгоритм реализации:
Номенклатура + Количество + Цена + Склад.Пример функции для формирования ключа строки:
Функция ПолучитьКлючСтроки(СтрокаТЧ, МассивПолей)
Результат = "";
Для Каждого ИмяПоля Из МассивПолей Цикл
Значение = СтрокаТЧ[ИмяПоля];
Результат = Результат + "_" + СокрЛП(Значение);
КонецЦикла;
Возврат Результат;
КонецФункции
Ограничение метода: Если в документе будут две абсолютно идентичные строки (одинаковый товар, цена и количество), хэш-метод не сможет их различить при удалении одной из них. Платформа воспримет это просто как уменьшение общего количества вхождения таких строк.
Выясним, как сделать решение «красивым» и универсальным, о чем просил автор темы. В современных версиях 8.3 мы можем использовать Расширения конфигурации. Вместо того чтобы вручную заходить в каждый документ, мы можем программно или через групповую обработку добавить реквизит ИдентификаторСтроки в нужные ТЧ внутри расширения.
Это позволит сохранить основную конфигурацию на поддержке и централизованно управлять логикой заполнения. В сочетании с общим модулем и подпиской на события, это создает элегантную архитектуру для системы аудита.
Проанализировав все варианты, подведем итог:
Помните, что добавление индексированного ГУИДа в таблицы с миллионами строк может сказаться на производительности записи, поэтому применяйте этот подход только там, где детализация до строки действительно критически важна для бизнеса.