При разработке конфигураций для учебных заведений часто возникает задача контроля данных: необходимо исключить повторное зачисление студента, если он уже числится в системе. В этой статье мы подробно разберем, как реализовать проверку наличия записей в регистре сведений Учащиеся при проведении документа ПриказОЗачислении. Мы проанализируем различные подходы — от простых запросов до профессиональной оптимизации с использованием временных таблиц и блокировок.
Рассмотрим стандартную ситуацию: у нас есть документ ПриказОЗачислении, в котором присутствует табличная часть Студенты. В этой табличной части хранится список будущих учащихся. Наша цель — в процедуре ОбработкаПроведения модуля объекта проверить, нет ли уже этих студентов в регистре сведений Учащиеся. Если хотя бы один студент уже зачислен, проведение документа должно быть прервано с выводом соответствующего сообщения пользователю.
Важно помнить, что в профессионально разработанной системе поле Студент в документе и измерение Студент в регистре должны иметь тип СправочникСсылка.Студенты (или ФизическиеЛица), а не обычную строку. Это позволяет платформе 1С эффективно работать с индексами и обеспечивать ссылочную целостность данных.
Самый простой и понятный способ — собрать все ссылки на студентов из табличной части документа в массив и передать этот массив в качестве параметра запроса. Проанализируем, как это выглядит в коде:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// 1. Собираем список студентов из табличной части документа
СписокСтудентов = Студенты.ВыгрузитьКолонку("Студент");
// 2. Создаем запрос для проверки наличия записей в регистре
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Учащиеся.Студент КАК Студент
|ИЗ
| РегистрСведений.Учащиеся КАК Учащиеся
|ГДЕ
| Учащиеся.Студент В (&СписокСтудентов)";
Запрос.УстановитьПараметр("СписокСтудентов", СписокСтудентов);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
// 3. Если запрос нашел записи, значит студенты уже есть в регистре
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Студент " + Выборка.Студент + " уже зачислен ранее!";
Сообщение.Сообщить();
КонецЦикла;
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Этот метод хорош своей простотой, однако у него есть недостатки: он не учитывает периодичность регистра и может работать медленно при очень больших списках студентов в одном документе.
Для более сложных систем рекомендуется использовать временные таблицы. Это позволяет избежать ограничений SQL на количество параметров в условии ГДЕ ... В (...) и дает возможность точно определить, какие именно строки документа являются ошибочными. Рассмотрим этот алгоритм:
// Внутри процедуры ОбработкаПроведения
Запрос = Новый Запрос;
МенеджерВТ = Новый МенеджерВременных Таблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Помещаем данные документа во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ
| ДокСтуденты.Студент КАК Студент,
| ДокСтуденты.НомерСтроки КАК НомерСтроки
|ПОМЕСТИТЬ ВТ_СтудентыДокумента
|ИЗ
| &ТЧ_Студенты КАК ДокСтуденты";
Запрос.УстановитьПараметр("ТЧ_Студенты", Студенты.Выгрузить());
Запрос.Выполнить();
// Основной запрос проверки
Запрос.Текст =
"ВЫБРАТЬ
| ВТ.НомерСтроки КАК НомерСтроки,
| ВТ.Студент КАК Студент
|ИЗ
| ВТ_СтудентыДокумента КАК ВТ
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Учащиеся КАК РегУчащиеся
| ПО ВТ.Студент = РегУчащиеся.Студент";
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
ТекстСообщения = СтрШаблон("Строка %1: Студент %2 уже присутствует в регистре!", Выборка.НомерСтроки, Выборка.Студент);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , , "Студенты[" + (Выборка.НомерСтроки - 1) + "].Студент", Отказ);
КонецЦикла;
КонецЕсли;
Выясним причину, по которой мы вообще делаем эти проверки. Если регистр Учащиеся является **независимым**, то записи в нем могут создаваться вручную, и риск дублирования велик. Однако в 1С существует механизм **подчинения регистра регистратору**.
Если мы установим для регистра Учащиеся режим записи Записывать выбранные и назначим документ ПриказОЗачислении регистратором, то при проведении документа записи будут формироваться автоматически через набор записей. В этом случае платформа сама контролирует уникальность записей в рамках одного документа. Однако для контроля уникальности по разным документам (чтобы нельзя было зачислить одного студента двумя разными приказами), программная проверка в ОбработкаПроведения всё равно остается необходимой.
Проанализируем несколько критически важных моментов, без которых решение может работать некорректно:
Учащиеся периодический, то студент может быть зачислен, потом отчислен, а затем зачислен снова. В этом случае в запросе нужно использовать виртуальную таблицу СрезПоследних на дату документа, чтобы проверить текущий статус студента.БлокировкаДанных. Мы должны заблокировать записи в регистре по списку студентов из документа перед выполнением запроса.Свернуть() для временной таблицы или предварительно проверить ТЧ программно.Студент в регистре имеет свойство Индексировать. Это критично для скорости работы запроса при накоплении в базе десятков тысяч записей.Таким образом, правильная реализация проверки включает не только написание Запроса, но и учет бизнес-логики (состояние студента), обеспечение целостности через Блокировки и удобство интерфейса через СообщенияПользователю с привязкой к конкретным строкам документа.