В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда стандартные методы работы с регистрами сведений ведут себя неочевидно. Одной из таких проблем является невозможность удаления записи из независимого периодического регистра сведений, даже если все данные для отбора кажутся верными. Рассмотрим подробнее, почему поле Период может принимать пустое значение (01.01.0001) при попытке программной записи и как правильно организовать удаление данных.
При использовании объекта РегистрСведенийМенеджерЗаписи для удаления конкретной строки, система требует точного указания ключа записи. В периодическом регистре ключом является комбинация всех измерений и значения поля Период. Разберем типичный сценарий: разработчик получает данные из запроса, помещает их в структуру и пытается передать в менеджер записи. Однако метод Прочитать() не находит запись, а отладчик показывает, что поле Период осталось пустым.
Выясним основные причины такого поведения:
Движение.Период = Структура.Дата может не сработать корректно в некоторых контекстах, если не выполнено явное приведение типов.Оператор, Компания и Водитель), а вы заполняете в менеджере записи только Оператор и Период, метод Прочитать() всегда будет возвращать Ложь, так как ключ записи определен не полностью.Рассмотрим ситуацию, когда нам необходимо удалить запись, имея на руках результат запроса. Проанализируем исправленный код, который учитывает обращение к полям выборки и корректную установку параметров:
Процедура УдалитьЗаписьРегистра(СтруктураОтбора) Экспорт
// Создаем объект менеджера записи для конкретного регистра
МенеджерЗаписи = РегистрыСведений.Вызовы.СоздатьМенеджерЗаписи();
// Получаем данные из структуры (предполагаем, что в структуре лежит результат запроса)
// Важно: Период в периодическом регистре является частью ключа!
МенеджерЗаписи.Период = СтруктураОтбора.Запись.Период;
// Заполняем ВСЕ измерения, которые есть в регистре
МенеджерЗаписи.Оператор = СтруктураОтбора.Запись.Оператор;
// Если есть другие измерения, их тоже нужно указать:
// МенеджерЗаписи.Компания = СтруктураОтбора.Запись.Компания;
// Пытаемся прочитать запись из базы данных по установленным полям
МенеджерЗаписи.Прочитать();
// Если запись найдена, удаляем ее
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Удалить();
Сообщить("Запись успешно удалена");
Иначе
Сообщить("Запись не найдена, проверьте корректность заполнения всех измерений");
КонецЕсли;
КонецПроцедуры
Важный момент: Обратите внимание на свойство стандартного реквизита Период в конфигураторе. Проверьте вкладку "Данные" вашего регистра, выделите Период в списке стандартных реквизитов и убедитесь, что свойство "Заполнять из данных заполнения" установлено в значение "Истина". Это позволяет платформе более гибко работать с передачей значений в этот реквизит при программном создании менеджера.
Если работа с МенеджерЗаписи вызывает сложности или требуется удалить сразу несколько записей, подходящих под условие, правильнее использовать РегистрСведенийНаборЗаписей. Этот метод считается более надежным, так как он работает напрямую с таблицей базы данных через механизм отборов.
Разберем по шагам, как очистить конкретную запись через пустой набор:
Процедура УдалитьЗаписьЧерезНабор(ТекущийПериод, ТекущийОператор) Экспорт
// Создаем набор записей
Набор = РегистрыСведений.Вызовы.СоздатьНаборЗаписей();
// Устанавливаем отборы по всем ключевым полям.
// Для периодического регистра Период является стандартным реквизитом отбора.
Набор.Отбор.Период.Установить(ТекущийПериод);
Набор.Отбор.Оператор.Установить(ТекущийОператор);
// Записываем пустой набор.
// Параметр Истина означает замещение существующих записей, попадающих в отбор.
// Так как мы не добавляли строк в Набор, записи в базе, подходящие под отбор, будут удалены.
Набор.Записать(Истина);
КонецПроцедуры
Проанализируем преимущества этого подхода. Во-первых, нам не нужно вызывать метод Прочитать(), что экономит ресурсы сервера. Во-вторых, если в регистре по какой-то причине оказалось две записи на одну секунду (что возможно при определенных настройках периодичности), набор записей корректно удалит их обе, в то время как менеджер записи может выдать ошибку неуникальности.
При работе с периодическими регистрами сведений крайне важно помнить о точности типа Дата в 1С. Даже если периодичность регистра установлена "В пределах секунды", переменная в коде может содержать миллисекунды (например, при получении из внешних систем или сложных вычислений). При этом в самой базе данных регистра миллисекунды отсекаются.
Посмотрим на пример, который поможет избежать проблем при поиске записи:
// Принудительно приводим дату к началу секунды,
// чтобы гарантировать совпадение с данными в регистре
НужнаяДата = НачалоСекунды(Структура.Период);
МенеджерЗаписи = РегистрыСведений.Вызовы.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = НужнаяДата;
// ... заполнение остальных полей
Использование функции НачалоСекунды гарантирует, что мы передаем в Период именно то значение, которое хранится в индексе регистра. Это критично для метода Прочитать().
Часто программисты пытаются установить отбор по периоду в наборе записей так же, как по обычным измерениям, используя метод Добавить() в коллекции отбора. Выясним, почему это приводит к ошибке "Поле не найдено".
В независимом периодическом регистре Период не является измерением, это стандартный реквизит. Поэтому он уже присутствует в коллекции Отбор набора записей по умолчанию. К нему нужно обращаться напрямую через точку: Набор.Отбор.Период. Попытка программно добавить новое поле с именем "Период" в отбор вызовет исключение платформы.
Подводя итог, можно выделить следующий алгоритм действий при возникновении проблем с назначением даты в Период:
МенеджерЗаписи.Выбран() и работает стабильнее.Период передается объект типа Дата, а не строка или неопределено.Период в конфигураторе.Соблюдение этих правил позволит вам эффективно управлять данными в регистрах сведений и избегать трудноуловимых ошибок в логике удаления записей.