Как отобрать и удалить записи независимого регистра сведений по значению ресурса

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке на платформе 1С:Предприятие программисты часто сталкиваются с особенностью работы независимых регистров сведений: стандартный механизм отбора в объекте НаборЗаписей работает исключительно по измерениям. Если перед нами стоит задача найти и удалить записи, ориентируясь на значение ресурса (например, найти все записи по конкретной номенклатуре в регистре КодыТоваровПодключаемогоОборудованияOffline), мы не можем просто установить фильтр в наборе записей. Это ограничение часто приводит к появлению логических дублей, когда одна и та же номенклатура оказывается привязана к разным кодам или планам обмена.

В данной статье мы подробно разберем, как обойти это ограничение, проанализируем программный код для очистки регистра и рассмотрим способы оптимизации этой операции для обеспечения высокой производительности системы.

Анализ проблемы: почему нельзя сделать простой отбор

В архитектуре 1С измерения регистра сведений составляют его уникальный ключ. Платформа автоматически индексирует измерения, что позволяет мгновенно получать к ним доступ. Ресурсы же предназначены для хранения целевых данных. По умолчанию поиск по ресурсу требует полного сканирования таблицы базы данных, что крайне неэффективно. Именно поэтому объект Отбор в методах СоздатьНаборЗаписей() не поддерживает поля, являющиеся ресурсами или реквизитами.

Рассмотрим ситуацию на примере регистра КодыТоваровПодключаемогоОборудованияOffline. Его измерения — это ПравилоОбмена и Код (SKU). Номенклатура является ресурсом. Если мы хотим перезаписать SKU для конкретного товара, нам сначала нужно найти все старые записи, где эта Номенклатура фигурирует, независимо от того, какие там были правила или коды, и удалить их.

Решение задачи: алгоритм «Запрос — Удаление — Запись»

Для реализации этой задачи мы применим проверенный алгоритм, состоящий из трех этапов. Разберем каждый из них подробно.

  1. Поиск ключей записей через запрос: Мы извлекаем значения всех измерений (ключевых полей) для тех строк, где ресурс соответствует нашему условию.
  2. Программное удаление по измерениям: Используя полученные данные, мы инициализируем НаборЗаписей с отбором по измерениям и очищаем старые данные.
  3. Создание новой записи: Записываем актуальную информацию.

Реализация поиска и удаления: разбираем код

Рассмотрим пример кода, который позволяет выполнить очистку регистра перед записью новых данных. В этом примере мы используем запрос для получения значений измерений ПравилоОбмена и Код по конкретной ссылке на номенклатуру.


ЗапросСКУ = Новый Запрос;
ЗапросСКУ.Текст = 
    "ВЫБРАТЬ
    |   КодыТоваров.ПравилоОбмена КАК ПравилоОбмена,
    |   КодыТоваров.Код КАК Код
    |ИЗ
    |   РегистрСведений.КодыТоваровПодключаемогоОборудованияOffline КАК КодыТоваров
    |ГДЕ
    |   КодыТоваров.Номенклатура = &Номенклатура";

ЗапросСКУ.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
РезультатЗапроса = ЗапросСКУ.Выполнить();

Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        // Создаем набор записей для каждой найденной комбинации измерений
        НаборДляУдаления = РегистрыСведений.КодыТоваровПодключаемогоОборудованияOffline.СоздатьНаборЗаписей();
        НаборДляУдаления.Отбор.ПравилоОбмена.Установить(Выборка.ПравилоОбмена);
        НаборДляУдаления.Отбор.Код.Установить(Выборка.Код);
        
        // Записываем пустой набор, что фактически удаляет записи, попавшие в отбор
        НаборДляУдаления.Записать();
    КонецЦикла;
КонецЕсли;

В данном фрагменте кода мы сначала выполняем Запрос, чтобы получить «координаты» записей в пространстве измерений. Затем в цикле мы используем НаборЗаписей. Обратите внимание: метод Записать() без добавления новых строк в набор эффективно удаляет все записи из базы данных, которые соответствуют установленному фильтру в свойстве Отбор.

Оптимизация производительности: на что обратить внимание

Предложенный выше метод является рабочим, однако при массовой обработке данных (например, при полной перегрузке справочника товаров) он может замедлить работу системы. Проанализируем, как можно улучшить этот процесс.

1. Индексация ресурсов. Чтобы запрос выполнялся мгновенно даже на больших таблицах, необходимо убедиться, что для ресурса Номенклатура в метаданных установлено свойство Индексировать. Это создаст в СУБД индекс по данному полю, и поиск в запросе будет происходить по сбалансированному дереву, а не путем перебора всех записей регистра.

2. Использование транзакций. Если вы удаляете и записываете данные в цикле, обязательно оберните весь блок кода в транзакцию. Это гарантирует целостность данных и значительно ускорит запись за счет уменьшения количества обращений к диску. Используйте конструкцию НачатьТранзакцию() и ЗафиксироватьТранзакцию().

3. Минимизация вызовов Записать(). Если логика позволяет, старайтесь объединять удаления. Однако для независимого регистра сведений, если записи имеют разные значения измерений, каждый НаборЗаписей с уникальным отбором все равно потребует отдельного вызова метода Записать().

Альтернативный подход: Менеджер записи

Если вам необходимо работать ровно с одной записью, вместо набора записей можно использовать МенеджерЗаписи. Это объект, который позволяет обращаться к конкретной строке регистра как к объекту. Рассмотрим, как это выглядит:


МенеджерЗаписи = РегистрыСведений.КодыТоваровПодключаемогоОборудованияOffline.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ПравилоОбмена = Выборка.ПравилоОбмена;
МенеджерЗаписи.Код = Выборка.Код;
МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда
    МенеджерЗаписи.Удалить();
КонецЕсли;

Использование МенеджерЗаписи делает код более читаемым, когда речь идет об удалении конкретной строки, найденной ранее. Однако помните, что для массовых операций НаборЗаписей обычно работает быстрее.

Архитектурные рекомендации

Проанализируем ситуацию: если в вашей системе часто возникает потребность искать данные в регистре по номенклатуре, возможно, стоит пересмотреть состав измерений. Если Номенклатура станет измерением, потребность в сложных запросах и предварительных удалениях отпадет сама собой — платформа обеспечит уникальность и возможность прямого отбора встроенными средствами.

Однако в типовых решениях (например, в подсистеме обмена с подключаемым оборудованием) структура регистра жестко задана разработчиками фирмы «1С». В таких случаях использование запроса к ключам измерений остается единственным и наиболее правильным способом управления данными. Выясним причину дублирования: часто это происходит из-за того, что в разных правилах обмена для одной номенклатуры назначаются разные SKU. Регулярная очистка регистра по предложенному алгоритму поможет поддерживать базу в актуальном состоянии и избежать ошибок при выгрузке на кассовое оборудование.

← На главную