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