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

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

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

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

Ограничение платформы: почему нельзя просто установить отбор?

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

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

Способ №1: Удаление через запрос и менеджер записи

Это самый прямолинейный способ, который не требует изменения структуры конфигурации. Идея заключается в том, чтобы сначала найти все записи нужного типа с помощью запроса, а затем удалить их по одной.

Рассмотрим пошагово реализацию этого метода:

  1. Создаем запрос к таблице регистра сведений.
  2. Используем оператор ССЫЛКА или функцию ТИПЗНАЧЕНИЯ для фильтрации записей.
  3. Выбираем все ключевые поля (все измерения регистра).
  4. Обходим результат запроса и удаляем записи.

Проанализируем пример кода для этого метода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	МойРегистр.ОбъектБазыСсылка КАК ОбъектБазыСсылка,
    |	МойРегистр.КодВДругойБазе КАК КодВДругойБазе
    |ИЗ
    |	РегистрСведений.МойРегистр КАК МойРегистр
    |ГДЕ
    |	МойРегистр.ОбъектБазыСсылка ССЫЛКА Справочник.Справочник1";

РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    МенеджерЗаписи = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.ОбъектБазыСсылка = ВыборкаДетальныеЗаписи.ОбъектБазыСсылка;
    МенеджерЗаписи.КодВДругойБазе = ВыборкаДетальныеЗаписи.КодВДругойБазе;
    МенеджерЗаписи.Удалить();
КонецЦикла;

Важный нюанс: использование РегистрСведенийМенеджерЗаписи удобно для удаления небольшого количества строк. Однако, если записей тысячи, это будет работать медленно, так как на каждое удаление инициируется отдельная транзакция и обращение к СУБД. В таком случае лучше группировать записи или использовать наборы.

Способ №2: Оптимизация через вспомогательное измерение «Тип объекта»

Как проанализировали участники обсуждения, наиболее правильным и производительным решением с точки зрения архитектуры является добавление дополнительного измерения. Назовем его ТипОбъекта.

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

Посмотрим на преимущества этого подхода:

Пример реализации удаления с дополнительным измерением:


Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
// Устанавливаем отбор по новому измерению
Набор.Отбор.ТипОбъекта.Установить("Справочник1");
// Записываем пустой набор с флагом Замещать = Истина
Набор.Записать(Истина);

После очистки мы можем просто заполнить этот же набор новыми данными для Справочник1 и снова вызвать Записать(Ложь) (или Истина, если мы объединили очистку и запись в один блок).

Способ №3: Использование временных таблиц и полной перезаписи (Массовый метод)

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

  1. Запросом выбираем из регистра все записи, которые НЕ относятся к удаляемому типу (т.е. те, что нужно сохранить).
  2. Выгружаем их в ТаблицуЗначений.
  3. Полностью очищаем регистр (или его сегмент по другим измерениям).
  4. Добавляем в ТаблицуЗначений новые записи для Справочник1.
  5. Записываем итоговую таблицу обратно в регистр через набор записей.

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


// 1. Получаем данные, которые должны остаться
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ * ИЗ РегистрСведений.МойРегистр 
    | ГДЕ НЕ ОбъектБазыСсылка ССЫЛКА Справочник.Справочник1";
ТаблицаСохраняемыхДанных = Запрос.Выполнить().Выгрузить();

// 2. Подготавливаем набор записей
Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
// ВАЖНО: Если есть другие ведущие измерения, установите по ним отбор здесь!

// 3. Загружаем старые (сохраненные) данные в набор
Набор.Загрузить(ТаблицаСохраняемыхДанных);

// 4. Добавляем новые данные в этот же набор
НоваяЗапись = Набор.Добавить();
НоваяЗапись.ОбъектБазыСсылка = СсылкаНаСправочник1;
НоваяЗапись.КодВДругойБазе = "НовыйКод";

// 5. Записываем всё одним махом
Набор.Записать(Истина);

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

Резюме и рекомендации

Проанализировав все варианты, можно сделать следующие выводы:

  1. Если вам нужно разовое решение или данных в регистре немного — используйте Способ №1 (Запрос + МенеджерЗаписи). Это быстро в плане написания кода и не требует доработки метаданных.
  2. Если вы проектируете систему «с нуля» или регистр будет интенсивно расти — обязательно внедрите Способ №2 (Дополнительное измерение с типом). Это стандарт индустрии для решения подобных задач, обеспечивающий максимальную скорость работы.
  3. Если вы столкнулись с необходимостью массовой обработки данных в закрытой конфигурации (где нельзя менять структуру) — используйте Способ №3 (Полная перезапись через ТЗ).

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

← На главную