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