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