Как правильно реализовать проверку данных в таблице и их запись в регистр сведений

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача синхронизации данных, введенных пользователем в таблицу на форме, с записями в регистре сведений. Типичный сценарий: пользователь отмечает одну из строк как «основную» (используя флажок типа Булево), и это изменение должно мгновенно или при сохранении объекта отразиться в базе данных. Однако при реализации такой логики начинающие разработчики часто сталкиваются с ошибками блокировок или дублирования ключей записей. Разберем пошагово, как решить эти проблемы.

Анализируем причину ошибки «Запись с такими полями уже существует»

Рассмотрим ситуацию, когда при попытке записи набора записей регистра сведений система выдает ошибку о существовании записи. Выясним причину этого поведения. В 1С Регистр сведений — это структура, уникальность записей в которой определяется комбинацией его измерений. Если мы пытаемся добавить в набор две строки, у которых все измерения (например, Изделие и Ресурс) совпадают, платформа выдаст исключение еще до момента физической записи в базу данных.

Проанализируем типичную ошибку в коде: когда внутри цикла по строкам таблицы значений каждый раз создается новый объект НаборЗаписей, устанавливается отбор и вызывается метод Записать(). Если в таблице есть строки с одинаковыми ключевыми полями, или если отбор установлен недостаточно точно, система конфликтует с уже имеющимися данными. Кроме того, использование цикла для записи каждой строки по отдельности крайне неэффективно с точки зрения производительности.

Реализация логики «радиокнопки» (единственного флажка)

Когда нам нужно, чтобы в колонке ПризнакОсновногоРесурса только одна строка имела значение Истина, мы должны программно снимать флажки с остальных строк при изменении текущей. Посмотрим, как это сделать оптимально на клиенте:


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

    // Если пользователь установил флаг, снимаем его во всех остальных строках
    Если ТекущиеДанные.ПризнакОсновногоРесурса Тогда
        Для Каждого СтрокаТЧ Из ТаблицаРесурсыИзделия Цикл
            Если СтрокаТЧ <> ТекущиеДанные Тогда
                СтрокаТЧ.ПризнакОсновногоРесурса = Ложь;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

В этом примере мы используем простой обход коллекции ТаблицаРесурсыИзделия. Обратите внимание, что мы меняем данные только в памяти (на форме), не обращаясь к серверу на каждое нажатие. Это значительно ускоряет работу интерфейса.

Оптимальная архитектура записи: Набор записей vs Менеджер записи

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

  1. РегистрСведенийНаборЗаписей — предназначен для работы с группой записей, отобранных по определенному правилу. Это основной инструмент для массового обновления данных. При вызове метода Записать(Истина) система сначала удаляет все старые записи в базе, попадающие под установленный Отбор, и записывает новые из коллекции набора.
  2. РегистрСведенийМенеджерЗаписи — удобен, когда нужно изменить или прочитать ровно одну конкретную запись. Он позволяет работать с записью как с объектом: Прочитать(), изменить ресурсы, Записать().

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

Проблема пустой ссылки и момент записи

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

Рекомендуется выполнять запись в регистр не в момент нажатия на флажок в таблице, а в обработчике ПриЗаписиНаСервере основного объекта. Таким образом, данные регистра будут сохранены в одной транзакции с самим объектом. Это исключает появление «мусорных» записей, если пользователь передумал сохранять документ после изменения флажка.

Пример правильной серверной процедуры записи

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


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

Дополнительные советы по повышению удобства

Проанализируем еще несколько приемов, которые помогут сделать решение более профессиональным:

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

← На главную