В процессе разработки в среде 1С:Предприятие часто возникает задача программного удаления данных из регистров сведений. Это может быть связано с отменой каких-либо действий пользователя, очисткой временных данных или корректировкой ошибочных записей. В этой статье мы подробно разберем, как правильно реализовать удаление одной или нескольких записей из независимого регистра сведений, рассмотрим различные подходы и проанализируем нюансы, которые помогут избежать типичных ошибок.
Когда нам нужно удалить одну конкретную запись, значения всех измерений которой нам известны, удобнее всего использовать РегистрСведенийМенеджерЗаписи. Этот объект работает по аналогии с объектом справочника: мы создаем его, заполняем ключевые поля и вызываем команду удаления.
Рассмотрим пример кода, который демонстрирует этот подход:
Процедура УдалитьЗаписьЧерезМенеджер(ВыбраннаяВалюта, ДатаЗаписи)
// Создаем объект менеджера записи для конкретного регистра
ЗаписьРС = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
// Заполняем ВСЕ измерения регистра, чтобы однозначно идентифицировать запись
ЗаписьРС.Период = ДатаЗаписи;
ЗаписьРС.Валюта = ВыбраннаяВалюта;
// Вызываем метод Удалить.
// Если запись с такими измерениями существует, она будет стерта.
ЗаписьРС.Удалить();
КонецПроцедуры
Важный нюанс: как было отмечено в обсуждении, вызывать метод Прочитать() перед Удалить() не обязательно, если вы точно знаете значения измерений. Однако, если вы хотите убедиться, что запись существует перед ее удалением, можно использовать следующую конструкцию:
ЗаписьРС = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
// Заполнение измерений...
ЗаписьРС.Прочитать();
Если ЗаписьРС.Выбран() Тогда
ЗаписьРС.Удалить();
КонецЕсли;
Проанализируем ситуацию: если в регистре много измерений, вы обязаны заполнить каждое из них. Если хотя бы одно измерение будет пропущено или заполнено неверно, система либо не найдет запись, либо (в редких случаях при неполном ключе) поведение может быть непредсказуемым.
Если стоит задача удалить не одну запись, а целую группу (например, все записи по конкретному контрагенту или за определенный день), использование Менеджера записи в цикле будет крайне неэффективным. В этом случае мы используем РегистрСведенийНаборЗаписей.
Рассмотрим самый быстрый способ удаления данных по фильтру:
НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
// Устанавливаем отбор по нужному измерению
НаборЗаписей.Отбор.Номенклатура.Установить(Объект.Номенклатура);
// Записываем пустой набор.
// Параметр Истина означает, что мы замещаем существующие в базе данные этим пустым набором.
НаборЗаписей.Записать(Истина);
Выясним причину, почему этот способ считается "опасным". Если по какой-то причине отбор не будет установлен (например, в переменной Объект.Номенклатура окажется Неопределено или пустая ссылка), и вы выполните Записать(Истина), система может очистить весь регистр. Поэтому всегда проверяйте заполнение параметров отбора перед записью набора.
Часто задача звучит так: "Пользователь видит список строк в таблице на форме, нажимает кнопку, и строка должна исчезнуть и из таблицы, и из базы". Разберем по шагам, как это реализовать на управляемых формах, используя данные из обсуждения.
На стороне сервера мы выполняем удаление из регистра, а на стороне клиента — из визуальной таблицы:
&НаСервере
Процедура УдалитьЗаписьИзРегистраНаСервере(ДанныеСтроки)
МенеджерЗаписи = РегистрыСведений.ВашРегистр.СоздатьМенеджерЗаписи();
// Копируем данные из строки таблицы в менеджер записи
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ДанныеСтроки);
// Для периодических регистров важно учитывать точное время
МенеджерЗаписи.Период = ДанныеСтроки.Период;
МенеджерЗаписи.Удалить();
КонецПроцедуры
&НаКлиенте
Процедура КомандаУдалить(Команда)
ТекущиеДанные = Элементы.ТаблицаДанных.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// 1. Удаляем из базы
УдалитьЗаписьИзРегистраНаСервере(ТекущиеДанные);
// 2. Удаляем из коллекции на форме
Идентификатор = ТекущиеДанные.ПолучитьИдентификатор();
Объект.ТаблицаДанных.Удалить(Объект.ТаблицаДанных.НайтиПоИдентификатору(Идентификатор));
КонецЕсли;
КонецПроцедуры
Если ваш регистр является периодическим, свойство Период является частью ключа записи. Разберем ситуацию: если в базе запись хранится со временем 14:30:05, а вы в коде передадите НачалоДня(ТекущаяДата), то метод Удалить() не сработает. Программа будет искать запись ровно на 00:00:00 и, не найдя ее, ничего не сделает.
Для корректного удаления в таких случаях рекомендуется:
RecordKey). Если вы работаете с динамическим списком, у каждой строки есть ключ записи, который можно передать в менеджер записи для автоматического заполнения всех измерений.Проанализируем ситуацию с точки зрения высоконагруженных систем. При программном удалении, особенно в циклах, важно помнить о блокировках данных. Если ваша процедура будет удалять записи слишком долго, другие пользователи не смогут записать новые данные в этот же регистр, возникнет ошибка "Конфликт блокировок".
Посмотрим на рекомендации по оптимизации:
Набор записей с установленным отбором. Это выполняется одной SQL-транзакцией и работает в десятки раз быстрее, чем удаление через Менеджер записи в цикле.БлокировкаДанных, если логика удаления сложная и включает предварительные проверки.Мы рассмотрели основные способы программного взаимодействия с регистром сведений при удалении данных. Подведем итоги:
Записать(Истина) без установленного отбора очистит весь регистр!Используя эти методы, вы сможете гибко и безопасно управлять данными в регистрах сведений ваших конфигураций.