Как получить значение поля Период последней записи регистра сведений

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает задача получить не просто значения ресурсов регистра сведений на определенную дату, но и узнать точный момент времени (дату и время), когда эта запись была внесена. Типичная ошибка начинающих разработчиков заключается в попытке обратиться к полю Период через структуру, возвращаемую методами менеджера регистра. Разберем детально, почему это происходит и какими способами можно получить заветную дату.

Почему метод ПолучитьПоследнее() выдает ошибку

Проанализируем работу метода ПолучитьПоследнее(). Согласно синтаксис-помощнику, данный метод предназначен для получения актуальных значений ресурсов. Важно понимать: он возвращает объект типа Структура, ключами которой являются имена только тех полей, которые определены в метаданных как ресурсы.

Рассмотрим пример, с которым столкнулся автор темы:


Отбор = Новый Структура("Сотрудник", ВыбранныйСотрудник);
Запись = РегистрыСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудников.ПолучитьПоследнее(ТекущаяДата(), Отбор);
// Попытка получить период:
МоментВремени = Запись.Период; // Ошибка: Поле объекта не обнаружено (Период)

В этой ситуации 1С справедливо сообщает об ошибке, так как в структуре Запись просто нет ключа Период. Система оптимизирована таким образом, чтобы не тянуть лишние данные из базы, если вы вызываете упрощенные методы получения среза. То же самое касается и метода СрезПоследних() менеджера регистра — он возвращает таблицу значений, в которой присутствуют колонки измерений и ресурсов, но системное поле Период в нее не включается автоматически.

Решение №1: Использование механизма запросов (Рекомендуемое)

Использование языка запросов — это самый эффективный и «чистый» способ решения задачи. При обращении к виртуальной таблице СрезПоследних через запрос, платформа предоставляет нам доступ ко всем полям, включая системное поле Период. Проанализируем, как правильно составить такой запрос.

Рассмотрим пошагово реализацию:

  1. Создаем объект Запрос.
  2. В тексте запроса обращаемся к виртуальной таблице СрезПоследних нужного регистра.
  3. В параметрах виртуальной таблицы указываем период (дату среза) и условие отбора (например, по сотруднику или показателю).
  4. В списке выбора явно указываем поле Период.

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РегистрСрезПоследних.Период КАК ПериодЗаписи,
    |	РегистрСрезПоследних.Значение КАК ЗначениеПоказателя
    |ИЗ
    |	РегистрСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудников.СрезПоследних(&ПериодСреза, Сотрудник = &Сотрудник) КАК РегистрСрезПоследних";

Запрос.УстановитьПараметр("ПериодСреза", ТекущаяДата());
Запрос.УстановитьПараметр("Сотрудник", НужныйСотрудник);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    Сообщить("Дата последней записи: " + Выборка.ПериодЗаписи);
    Сообщить("Значение показателя: " + Выборка.ЗначениеПоказателя);
КонецЕсли;

Преимущества этого метода: мы получаем ровно те данные, которые нам нужны, одним компактным вызовом к СУБД. Это работает значительно быстрее, чем перебор записей в объектной модели.

Решение №2: Использование метода Выбрать() (Объектная модель)

Если по каким-то причинам вы категорически не хотите использовать запросы (хотя в сообществе 1С это считается плохой практикой для подобных задач), можно воспользоваться методом Выбрать(). В отличие от ПолучитьПоследнее(), этот метод возвращает объект РегистрСведенийВыборка, который содержит полноценные записи со всеми полями.

Выясним нюансы этого подхода. Метод Выбрать() читает физическую таблицу регистра, а не виртуальный срез. Это значит, что если у сотрудника было 100 изменений показателя за год, метод вернет все 100 записей. Чтобы найти именно последнюю, нам придется прибегнуть к хитрости с порядком обхода.


Отбор = Новый Структура("Сотрудник", НужныйСотрудник);
// Выбираем записи в обратном хронологическом порядке (если поддерживается платформой)
// или просто перебираем все до последней.
Выборка = РегистрыСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудников.Выбрать( , ТекущаяДата(), Отбор);

ПоследнийПериод = '00010101';
Пока Выборка.Следующий() Цикл
    // Так как выборка обычно упорядочена по периоду, 
    // последняя итерация даст нам самую свежую запись на момент ТекущаяДата()
    ПоследнийПериод = Выборка.Период;
КонецЦикла;

Если ПоследнийПериод <> '00010101' Тогда
    Сообщить("Период записи найден: " + ПоследнийПериод);
КонецЕсли;

Важное предостережение: данный метод крайне непроизводителен. Если история записей велика, система будет вынуждена прочитать и передать с сервера на клиент (или в код модуля) весь массив данных, чтобы вы просто взяли из него последнюю строку. Используйте этот способ только в исключительных случаях или при работе с заведомо малым объемом данных.

Решение №3: Менеджер записи (РегистрСведенийМенеджерЗаписи)

Рассмотрим еще один инструмент — МенеджерЗаписи. Он позволяет прочитать конкретную уникальную запись регистра. Однако здесь нас подстерегает «замкнутый круг»: чтобы метод Прочитать() отработал успешно, в отборе менеджера записи нужно указать значения всех измерений и точный период.

Посмотрим на логику:


Менеджер = РегистрыСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудников.СоздатьМенеджерЗаписи();
Менеджер.Сотрудник = НужныйСотрудник;
// Менеджер.Период = ??? <-- Мы же его и ищем!
Менеджер.Прочитать();

Таким образом, МенеджерЗаписи не подходит для поиска периода, он нужен только для изменения или чтения данных, когда дата уже известна.

Подведем итоги

Проанализировав все доступные инструменты платформы 1С, мы можем сделать следующие выводы:

  1. Метод ПолучитьПоследнее() — это «быстрый» способ получить состояние ресурсов, но он скрывает метаданные самой записи (период, регистратор).
  2. Для получения даты возникновения записи (поля Период) единственным профессиональным решением является использование Запроса к виртуальной таблице СрезПоследних.
  3. При написании запроса всегда старайтесь ограничивать выборку параметрами виртуальной таблицы (указывать дату и условия в скобках после имени таблицы), это существенно ускоряет работу базы данных.
  4. Если вы работаете в коде, который должен быть универсальным или не зависеть от языка запросов (что редкость), используйте Выбрать(), но помните о рисках замедления системы.

Помните, что архитектура 1С разделяет понятия «текущее значение» и «история изменений». Системное поле Период — это часть истории, и наиболее эффективно работать с ней позволяет именно механизм запросов.

← На главную