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