При программном удалении или перезаписи записей в независимых и периодических регистрах сведений разработчики нередко сталкиваются с ситуацией, когда код отрабатывает без ошибок, но строки в информационной базе остаются на месте. Разберем по шагам, почему возникает такое поведение, как компактно и безошибочно очищать записи с помощью набора записей или менеджера записи, а также выясним причину неожиданного поведения виртуальной таблицы среза последних.
Проанализируем стандартную ситуацию: разработчик формирует набор записей регистра, устанавливает значения отбора, считывает данные, вызывает очистку и записывает набор. Однако данные в базе не изменяются. Выясним причину, рассмотрев основные ошибки:
Ложь вместо Истина) или значение реквизита не совпадает в точности, отбор просто не находит целевую запись. При записи пустого набора удаляются только те строки, которые строго соответствуют установленному фильтру.Период к началу периода (например, 00:00:00). Если передать в отбор дату документа, содержащую точное время (часы, минуты, секунды), точное равенство не выполнится, и запись затронута не будет. Дату необходимо приводить функциями НачалоДня(), НачалоМесяца() в соответствии с метаданными.Период. Попытка установить отбор по обычному реквизиту или ресурсу вызовет ошибку платформы. При этом вид сравнения всегда фиксирован — строго «Равно».Рассмотрим исходный код, в котором присутствует избыточность:
НаборЗаписей = РегистрыСведений.Кос_НомераСчетов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Собственник.Значение = Источник.Кос_Собственник.Ссылка;
НаборЗаписей.Отбор.НомерЧислом.Значение = НомерБезПрефикса;
НаборЗаписей.Отбор.Удаленный.Значение = Ложь;
НаборЗаписей.Отбор.Период.Значение = Источник.Дата;
НаборЗаписей.Отбор.Собственник.Использование = Истина;
НаборЗаписей.Отбор.НомерЧислом.Использование = Истина;
НаборЗаписей.Отбор.Удаленный.Использование = Истина;
НаборЗаписей.Отбор.Период.Использование = Истина;
НаборЗаписей.Прочитать();
НаборЗаписей.Очистить();
НаборЗаписей.Записать(Истина);
Разберем, почему вызовы Прочитать() и Очистить() здесь не нужны. Вновь созданный объект РегистрСведенийНаборЗаписей изначально инициализируется пустым. Метод Записать() по умолчанию принимает параметр Замещать = Истина. Это означает, что платформа перед записью удаляет из информационной базы все записи, удовлетворяющие установленным отборам, и записывает то, что содержится в коллекции набора. Так как набор изначально пустой, чтение с диска и последующая очистка коллекции являются лишними операциями, замедляющими работу системы.
Кроме того, вместо раздельного присвоения свойств Значение и Использование следует применять метод Установить(). Посмотрим на оптимальный вариант кода:
НаборЗаписей = РегистрыСведений.Кос_НомераСчетов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Собственник.Установить(Источник.Кос_Собственник);
НаборЗаписей.Отбор.НомерЧислом.Установить(НомерБезПрефикса);
НаборЗаписей.Отбор.Удаленный.Установить(Ложь);
НаборЗаписей.Отбор.Период.Установить(НачалоДня(Источник.Дата));
// Пустой набор перезаписывает и удаляет существующие данные по отбору
НаборЗаписей.Записать();
Если требуется удалить ровно одну строку регистра, для которой точно известны ключевые поля, удобнее использовать РегистрСведенийМенеджерЗаписи. Этот объект работает с конкретной физической записью, адресуемой полным набором измерений и периодом. Разберем пример реализации:
МенеджерЗаписи = РегистрыСведений.Кос_НомераСчетов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Собственник = Источник.Кос_Собственник;
МенеджерЗаписи.НомерЧислом = НомерБезПрефикса;
МенеджерЗаписи.Удаленный = Ложь;
МенеджерЗаписи.Период = НачалоДня(Источник.Дата);
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Удалить();
КонецЕсли;
Нередко разработчики используют виртуальную таблицу СрезПоследних для выборки данных в рамках определенного года, передавая в качестве параметра дату начала года, и удивляются получению прошлогодних записей. Рассмотрим проблемный запрос:
ВЫБРАТЬ ПЕРВЫЕ 1
Кос_НомераСчетовСрезПоследних.НомерЧислом
ИЗ
РегистрСведений.Кос_НомераСчетов.СрезПоследних(
&ВыбПериод,
Собственник = &ВыбСобственник
И Удаленный = &ВыбУдаленный) КАК Кос_НомераСчетовСрезПоследних
УПОРЯДОЧИТЬ ПО
Кос_НомераСчетовСрезПоследних.НомерЧислом УБЫВ
Выясним причину такого поведения. Параметр Период виртуальной таблицы СрезПоследних задает момент времени (точку среза), а не интервал выборки. Платформа отбирает последние актуальные записи, дата которых меньше либо равна переданному значению. Если в &ВыбПериод передать НачалоГода(Источник.Дата), система вернет наиболее свежую запись на 1 января 00:00:00 — ею закономерно окажется запись, созданная в предыдущем году.
Если стоит задача выбрать данные строго за текущий календарный год (например, для расчета очередного номера счета), необходимо обращаться к реальной таблице регистра и ограничивать временной интервал в секции условий. Посмотрим на корректный текст запроса:
ВЫБРАТЬ
ЕСТЬNULL(МАКСИМУМ(Кос_НомераСчетов.НомерЧислом), 0) КАК МаксимальныйНомер
ИЗ
РегистрСведений.Кос_НомераСчетов КАК Кос_НомераСчетов
ГДЕ
Кос_НомераСчетов.Собственник = &ВыбСобственник
И Кос_НомераСчетов.Удаленный = &ВыбУдаленный
И Кос_НомераСчетов.Период >= &НачалоГода
Если регистр сведений задействован в механизме пользовательской нумерации, обратите внимание на многопользовательскую среду. Чтение максимального номера запросом с последующей записью нового значения без блокировок может приводить к дублированию номеров при параллельной работе пользователей. В таких сценариях перед выполнением запроса внутри транзакции необходимо накладывать исключительную управляемую блокировку через объект БлокировкаДанных по измерению Собственник.