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

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

В процессе разработки на платформе 1С часто возникает задача контроля хронологии событий. Например, нам может потребоваться запретить создание документа, если в регистре сведений уже существуют записи с более поздней датой, или просто вывести информационное сообщение пользователю. В этой статье мы подробно разберем, как извлечь дату последней записи и сравнить ее с текущим документом.

Выбор места для реализации проверки

Прежде всего, определимся, где именно должен располагаться наш код. Поскольку проверка должна срабатывать непосредственно перед сохранением данных в базу, оптимальным местом является обработчик события ПередЗаписью в модуле документа. Проанализируем, почему это важно: данный обработчик выполняется на сервере внутри транзакции записи, что гарантирует актуальность данных.

Рассмотрим базовую структуру в модуле документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Здесь будет наш код получения даты из регистра
    ДатаПоследнейЗаписи = ПолучитьДатуПоследнейЗаписи();
    
    Если ЗначениеЗаполнено(ДатаПоследнейЗаписи) И ДатаПоследнейЗаписи > Дата Тогда
        Сообщить("Внимание: в регистре есть более поздние записи от " + ДатаПоследнейЗаписи);
        // Если нужно прервать запись, раскомментируйте строку ниже:
        // Отказ = Истина;
    КонецЕсли;

КонецПроцедуры

Способ 1: Использование запроса к основной таблице (Классический подход)

Разберем вариант, предложенный участниками форума. Самый простой способ получить последнюю дату — обратиться к таблице регистра и использовать агрегатную функцию МАКСИМУМ для поля Период. Посмотрим на реализацию функции:


Функция ПолучитьДатуПоследнейЗаписи() Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	МАКСИМУМ(МойРегистр.Период) КАК ДатаПоследнейЗаписи
        |ИЗ
        |	РегистрСведений.МойРегистр КАК МойРегистр";
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() И Выборка.ДатаПоследнейЗаписи <> NULL Тогда
        Возврат Выборка.ДатаПоследнейЗаписи;
    Иначе
        Возврат '00010101'; // Пустая дата, если записей нет
    КонецЕсли;
КонецФункции

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

Способ 2: Виртуальные таблицы (Оптимизированный подход)

Для периодических регистров сведений платформа 1С предоставляет мощный инструмент — виртуальную таблицу СрезПоследних. Рассмотрим подробнее, почему этот метод предпочтительнее. Платформа оптимизирует такие запросы на уровне SQL, что обеспечивает максимально быстрое получение результата.

Выясним причину использования СрезПоследних: даже если нам не нужны значения ресурсов, сам факт получения последней записи через виртуальную таблицу работает эффективнее на больших объемах данных.


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

Запрос.УстановитьПараметр("ПериодДокумента", Дата); // Ищем записи на момент документа или ранее

Способ 3: Метод менеджера регистра «ПолучитьПоследнее»

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


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

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

Важность фильтрации по измерениям

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

Допустим, наш документ фиксирует цену товара. Нам нужно сравнить дату документа с последней установленной ценой именно для этого конкретного товара. В таком случае в запрос или в метод ПолучитьПоследнее необходимо передать фильтр.

Пример отбора в запросе:


Запрос.Текст = 
    "ВЫБРАТЬ МАКСИМУМ(Период) ИЗ РегистрСведений.ЦеныГде Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", ЭтотОбъект.Товар);

Обработка пустых значений и исключений

Разберем ситуацию, когда регистр пуст. При выполнении запроса с функцией МАКСИМУМ к пустой таблице, результатом будет значение NULL. В коде 1С необходимо обязательно проверять результат на NULL или использовать функцию ЕСТЬNULL(..., ДАТАВРЕМЯ(1,1,1)) прямо в тексте запроса. Это предотвратит ошибки при сравнении типов в операторе Если.

Также важно помнить о клиент-серверном взаимодействии. Все вышеперечисленные операции с объектом Запрос или менеджерами регистров должны выполняться в контексте &НаСервере. Если вы вызываете эту логику из модуля формы, убедитесь, что процедура имеет соответствующую директиву компиляции.

Транзакционные блокировки

В многопользовательской среде существует риск «состояния гонки» (race condition). Рассмотрим сценарий: два пользователя одновременно записывают документы. Пока первый выполняет проверку даты, второй уже успевает записать данные в регистр. В результате проверка первого пользователя окажется неактуальной.

Для предотвращения таких ситуаций профессиональные разработчики используют объект БлокировкаДанных. Мы блокируем диапазон записей в регистре на чтение до окончания транзакции текущего документа, гарантируя целостность бизнес-логики.

Подводя итог, можно сказать, что выбор метода зависит от архитектуры вашего решения. Для простых проверок достаточно запроса к МАКСИМУМ(Период), а для высоконагруженных систем лучше использовать виртуальные таблицы с четко заданными отборами по измерениям.

← На главную