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

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

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

Постановка задачи и анализ структуры данных

Рассмотрим стандартную ситуацию: у нас есть документ ПриказОЗачислении, в котором присутствует табличная часть Студенты. В этой табличной части хранится список будущих учащихся. Наша цель — в процедуре ОбработкаПроведения модуля объекта проверить, нет ли уже этих студентов в регистре сведений Учащиеся. Если хотя бы один студент уже зачислен, проведение документа должно быть прервано с выводом соответствующего сообщения пользователю.

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

Решение 1: Использование запроса с условием по списку (Базовый уровень)

Самый простой и понятный способ — собрать все ссылки на студентов из табличной части документа в массив и передать этот массив в качестве параметра запроса. Проанализируем, как это выглядит в коде:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // 1. Собираем список студентов из табличной части документа
    СписокСтудентов = Студенты.ВыгрузитьКолонку("Студент");
    
    // 2. Создаем запрос для проверки наличия записей в регистре
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Учащиеся.Студент КАК Студент
        |ИЗ
        |   РегистрСведений.Учащиеся КАК Учащиеся
        |ГДЕ
        |   Учащиеся.Студент В (&СписокСтудентов)";
    
    Запрос.УстановитьПараметр("СписокСтудентов", СписокСтудентов);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Если Не РезультатЗапроса.Пустой() Тогда
        // 3. Если запрос нашел записи, значит студенты уже есть в регистре
        Выборка = РезультатЗапроса.Выбрать();
        Пока Выборка.Следующий() Цикл
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Студент " + Выборка.Студент + " уже зачислен ранее!";
            Сообщение.Сообщить();
        КонецЦикла;
        
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры

Этот метод хорош своей простотой, однако у него есть недостатки: он не учитывает периодичность регистра и может работать медленно при очень больших списках студентов в одном документе.

Решение 2: Оптимизация через временные таблицы и левое соединение (Профессиональный уровень)

Для более сложных систем рекомендуется использовать временные таблицы. Это позволяет избежать ограничений SQL на количество параметров в условии ГДЕ ... В (...) и дает возможность точно определить, какие именно строки документа являются ошибочными. Рассмотрим этот алгоритм:

  1. Выгружаем табличную часть документа во временную таблицу.
  2. Соединяем её левым соединением с таблицей регистра сведений.
  3. Проверяем наличие записей в правой части соединения.

// Внутри процедуры ОбработкаПроведения
Запрос = Новый Запрос;
МенеджерВТ = Новый МенеджерВременных Таблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Помещаем данные документа во временную таблицу
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ДокСтуденты.Студент КАК Студент,
    |   ДокСтуденты.НомерСтроки КАК НомерСтроки
    |ПОМЕСТИТЬ ВТ_СтудентыДокумента
    |ИЗ
    |   &ТЧ_Студенты КАК ДокСтуденты";

Запрос.УстановитьПараметр("ТЧ_Студенты", Студенты.Выгрузить());
Запрос.Выполнить();

// Основной запрос проверки
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВТ.НомерСтроки КАК НомерСтроки,
    |   ВТ.Студент КАК Студент
    |ИЗ
    |   ВТ_СтудентыДокумента КАК ВТ
    |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Учащиеся КАК РегУчащиеся
    |       ПО ВТ.Студент = РегУчащиеся.Студент";

Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
    Выборка = Результат.Выбрать();
    Пока Выборка.Следующий() Цикл
        ТекстСообщения = СтрШаблон("Строка %1: Студент %2 уже присутствует в регистре!", Выборка.НомерСтроки, Выборка.Студент);
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , , "Студенты[" + (Выборка.НомерСтроки - 1) + "].Студент", Отказ);
    КонецЦикла;
КонецЕсли;

Архитектурный подход: Подчинение регистра регистратору

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

Если мы установим для регистра Учащиеся режим записи Записывать выбранные и назначим документ ПриказОЗачислении регистратором, то при проведении документа записи будут формироваться автоматически через набор записей. В этом случае платформа сама контролирует уникальность записей в рамках одного документа. Однако для контроля уникальности по разным документам (чтобы нельзя было зачислить одного студента двумя разными приказами), программная проверка в ОбработкаПроведения всё равно остается необходимой.

Важные технические нюансы

Проанализируем несколько критически важных моментов, без которых решение может работать некорректно:

Таким образом, правильная реализация проверки включает не только написание Запроса, но и учет бизнес-логики (состояние студента), обеспечение целостности через Блокировки и удобство интерфейса через СообщенияПользователю с привязкой к конкретным строкам документа.

← На главную