Как организовать поиск коллизий и проверку дублей в табличной части 1С?

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

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

Анализ типовых ошибок при проверке текущей строки

Рассмотрим распространенный фрагмент кода, в котором разберем ошибки логики и синтаксиса:


СтрТабЧасти = Элементы.Расписание.ТекущиеДанные;
Если СтрТабЧасти.Предмет = СтрТабЧасти.Предмет Тогда
    Если СтрТабЧасти.НомерПары = СтрТабЧасти.НомерПары Тогда 
        Отказ = Истина;
        Возврат;
        Сообщить = ("Дисциплина занята другой группой");
    КонецЕсли;
КонецЕсли;

Выясним основные причины, по которым данный код не выполняет поиск дублей по всей таблице:

  1. Сравнение реквизита самого с собой: условие СтрТабЧасти.Предмет = СтрТабЧасти.Предмет сравнивает значение в текущей редактируемой строке с этим же значением из той же строки. Это условие всегда возвращает Истина и не ищет совпадения в других строках.
  2. Ограничение контекстической строки: объект Элементы.Расписание.ТекущиеДанные возвращает только одну текущую строку табличной части. Он не предоставляет доступ ко всей коллекции для поиска пересечений.
  3. Ошибки порядка выполнения кода: оператор Возврат; размещен перед синтаксически неверным вызовом сообщения. До функции информирования пользователя управление не дойдет. Вызов синтаксически пишется как Сообщить("Текст").
  4. Неверный контекст события: переменная Отказ недоступна в событиях элементов формы (например, ПриИзменении). Она используется только в специализированных событиях формы или объекта.

Способы проверки дублей в табличной части

Разберем практические способы, которые позволяют проверить совпадение данных по всей табличной части документа.

Способ 1. Использование метода НайтиСтроки()

Метод НайтиСтроки() позволяет найти все строки, соответствующие заданной структуре отбора. Проанализируем пример выполнения такой проверки:


ТекущаяСтрока = Элементы.Расписание.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
    Возврат;
КонецЕсли;

Отбор = Новый Структура;
Отбор.Вставить("ДеньНедели", ТекущаяСтрока.ДеньНедели);
Отбор.Вставить("НомерПары", ТекущаяСтрока.НомерПары);
Отбор.Вставить("Кабинет", ТекущаяСтрока.Кабинет);

НайденныеСтроки = Объект.Расписание.НайтиСтроки(Отбор);

Если НайденныеСтроки.Количество() > 1 Тогда
    СообщитьПользователю = Новый СообщениеПользователю;
    СообщитьПользователю.Текст = "Выбранный кабинет уже занят на эту пару!";
    СообщитьПользователю.Сообщить();
    ТекущаяСтрока.Кабинет = Справочники.Кабинеты.ПустаяСсылка();
КонецЕсли;

Способ 2. Обход коллекции табличной части в цикле

Посмотрим на пример обхода всей табличной части с исключением текущей редактируемой строки:


ТекущаяСтрока = Элементы.Расписание.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
    Возврат;
КонецЕсли;

Для Каждого СтрИзТабЧасти Из Объект.Расписание Цикл
    Если СтрИзТабЧасти = ТекущаяСтрока Тогда
        Продолжить;
    КонецЕсли;
    
    Если СтрИзТабЧасти.ДеньНедели = ТекущаяСтрока.ДеньНедели
       И СтрИзТабЧасти.НомерПары = ТекущаяСтрока.НомерПары Тогда
       
        Если СтрИзТабЧасти.Кабинет = ТекущаяСтрока.Кабинет И ЗначениеЗаполнено(ТекущаяСтрока.Кабинет) Тогда
            ВызватьИсключение "Кабинет уже занят!";
        КонецЕсли;
        
    КонецЕсли;
КонецЦикл;

Способ 3. Проверка на сервере через запросы или Таблицу Значений

При проверке документа перед записью в событии ОбработкаПроверкиЗаполнения или ПередЗаписьюНаСервере выгрузим табличную часть и сгруппируем данные. Если результат группировки показывает количество записей больше 1 для одного временного слота, установим параметр Отказ = Истина.

Применение событий платформы для валидации

Рассмотрим, в каких событиях формы и объекта следует вызывать проверки:

  1. Событие ПриИзменении колонки: срабатывает сразу после выбора значения пользователем. Поскольку параметра Отказ здесь нет, при обнаружении коллизии следует очищать введенное значение и информировать пользователя с помощью СообщениеПользователю.
  2. Событие таблицы ПередОкончаниемРедактирования: содержит параметр Отказ. Установка Отказ = Истина блокирует завершение редактирования строки до тех пор, пока пользователь не исправит наложение.
  3. Событие ПередЗаписьюНаСервере: гарантирует, что непроверенные или некорректные данные не попадают в базу данных при сохранении документа.

Использование регистров сведений для составления расписания

Хотя проверку можно реализовать внутри табличной части документа, для задач составления расписания оптимальным архитектурным решением является использование объектов РегистрСведений. Хранение данных в регистре предотвращает наложение занятости между разными документами и оперативно показывает текущую загрузку аудиторий и преподавателей.

Для реализации логики контроля расписания спроектируем следующую структуру регистров сведений:

Регистр 1: ЗанятостьГрупп (периодический или независимый)

Регистр 2: ЗанятостьКабинетов

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

← На главную