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

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

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

Механизм работы с объектом НаборЗаписей

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

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


НаборЗаписей = РегистрыСведений.ОбращенияЗаписи.СоздатьНаборЗаписей();

// Установка отборов по всем ключевым измерениям
НаборЗаписей.Отбор.Пациент.Установить(Пациент);
НаборЗаписей.Отбор.ДатаПервичногоПосещения.Установить(ДатаПервичногоПосещения);
НаборЗаписей.Отбор.УникальныйИдентификаторПоказателейЗдоровья.Установить(УникальныйИдентификаторПоказателейЗдоровья);

// Чтение текущего состояния регистра по данным фильтрам
НаборЗаписей.Прочитать();

Если НаборЗаписей.Количество() = 0 Тогда
    // Если записей нет, добавляем новую строку в набор
    Запись = НаборЗаписей.Добавить();
Иначе
    // Если запись найдена, работаем с первой строкой набора
    Запись = НаборЗаписей[0];
КонецЕсли;

// Заполнение ресурсов и реквизитов
Запись.Пациент = Пациент;
Запись.ДатаПервичногоПосещения = ДатаПервичногоПосещения;
Запись.УникальныйИдентификаторПоказателейЗдоровья = УникальныйИдентификаторПоказателейЗдоровья;
Запись.ПоказательАртериальногоДавления = 120; // Пример ресурса

// Фиксация изменений в базе данных
НаборЗаписей.Записать();

Важный нюанс: метод Записать() по умолчанию принимает параметр Замещать = Истина. Это означает, что всё содержимое регистра, подходящее под установленный отбор, будет удалено и заменено содержимым вашего объекта НаборЗаписей. Если вы вызвали Прочитать(), изменили строку и записали — данные обновятся. Если вы НЕ вызвали Прочитать(), а просто добавили новую строку в пустой набор и записали его с установленным отбором — старая запись в базе будет удалена, а новая создана.

Использование Менеджера записи для работы с одной строкой

Если логика вашей обработки подразумевает изменение строго одной конкретной записи, то использование НабораЗаписей может быть избыточным. Выясним, как упростить код с помощью объекта МенеджерЗаписи. Этот объект работает аналогично записи справочника или документа.

Посмотрим на пример работы с менеджером записи:


МенеджерЗаписи = РегистрыСведений.ОбращенияЗаписи.СоздатьМенеджерЗаписи();

// Прямое заполнение измерений для поиска
МенеджерЗаписи.Пациент = Пациент;
МенеджерЗаписи.ДатаПервичногоПосещения = ДатаПервичногоПосещения;
МенеджерЗаписи.УникальныйИдентификаторПоказателейЗдоровья = УникальныйИдентификаторПоказателейЗдоровья;

// Попытка чтения записи из базы
МенеджерЗаписи.Прочитать();

Если Не МенеджерЗаписи.Выбран() Тогда
    // Если записи не существует, значения измерений уже заполнены выше
    // Можно дозаполнить ресурсы
КонецЕсли;

МенеджерЗаписи.ПоказательАртериальногоДавления = 130;
МенеджерЗаписи.Записать();

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

Проблема уникальности и «лишних» записей

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

Если вы получаете дубли, проверьте следующие моменты:

  1. Состав измерений в отборе: Если вы устанавливаете отбор только по одному измерению из трех, а потом вызываете Добавить() в цикле, система будет добавлять новые строки в набор, не видя существующих по другим измерениям.
  2. Изменение ключевых полей: Если одно из измерений (например, УникальныйИдентификаторПоказателейЗдоровья) получает новое значение при каждом запуске обработки, то для системы это всегда новая, уникальная запись.
  3. Периодичность: Если регистр периодический, в ключ записи добавляется поле Период. Даже если все измерения совпадают, но разница в дате/времени составляет хотя бы одну секунду (при соответствующей настройке), это будут разные записи.

Как разрешить запись нескольких одинаковых данных?

Рассмотрим ситуацию из сообщения №7: пользователю нужно записать одинаковые данные дважды (например, два посещения в один день). В стандартном регистре сведений это невозможно без изменения его структуры. Чтобы реализовать такую возможность, выполним одно из следующих действий:

Особенности транзакционной записи и блокировок

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


НачатьТранзакцию();
Попытка
    Набор = РегистрыСведений.ОбращенияЗаписи.СоздатьНаборЗаписей();
    // ... логика заполнения набора ...
    Набор.Записать();
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ЗаписатьЛогОшибок(ОписаниеОшибки());
    Сообщить("Ошибка при записи в регистр!");
КонецПопытки;

Использование транзакции гарантирует, что если при записи произойдет сбой (например, отключится питание или возникнет ошибка уникальности), база данных вернется в исходное состояние, и у вас не останется «битых» или частичных данных.

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

Рекомендации по очистке данных

Иногда требуется не обновить, а полностью «перезалить» данные по определенному критерию. Разберем, как сделать это правильно:

  1. Установите отбор (например, по конкретному пациенту).
  2. Создайте пустой набор записей.
  3. Вызовите Набор.Записать(Истина). Это удалит все старые записи по этому пациенту.
  4. Заполните этот же набор новыми данными и снова вызовите Записать().

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

← На главную