Как работает параметр метода Записать(Ложь) в регистрах сведений 1С

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

При разработке конфигураций на платформе 1С:Предприятие разработчики часто сталкиваются с методом Записать() у объектов РегистрСведенийМенеджерЗаписи и РегистрСведенийНаборЗаписей. В синтакс-помощнике указано, что необязательный параметр Замещать (булево) определяет режим замещения существующей записи. При значении Истина выполняется замещение, а при значении Ложь запись дописывается к уже существующим. У многих программистов возникает логичный вопрос: почему при вызове Записать(Ложь) с уже существующим набором ключевых полей возникает исключение «Запись с такими ключевыми полями уже существует», и в каких ситуациях этот режим действительно необходим?

Разберем детально логику работы параметра замещения, его влияние на транзакции и различия между объектами платформы.

Принцип работы параметра Замещать в объекте МенеджерЗаписи

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

Посмотрим на поведение метода Записать() менеджера записи при различных значениях параметра:

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

Проанализируем пример кода с созданием записи через менеджер:


НоваяЗапись = РегистрыСведений.СтатусПаллетоМест.СоздатьМенеджерЗаписи();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Документ = ОбъектАдресноеХранение;
НоваяЗапись.Сектор = Сектор;
НоваяЗапись.Ряд = Ряд;
НоваяЗапись.Паллет = Паллет;
НоваяЗапись.Ответственный = Ответственный;
НоваяЗапись.Причина = Причина;
НоваяЗапись.Заблокировано = Ложь;

// Попытка добавить запись без права перезаписи существующих данных
НоваяЗапись.Записать(Ложь);

Для чего и в каких сценариях использовать Записать(Ложь)

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

  1. Защита от случайной затирки данных. Если бизнес-логика требует создавать только новые записи (например, журнал регистрации уникальных событий или назначение ответственного лица на период), режим Замещать = Ложь гарантирует, что чужие или ранее зафиксированные данные не будут стерты повторным вызовом кода.
  2. Изменение ключевых полей через прочитанный менеджер. Если вы сначала вызвали Прочитать(), изменили ключевые измерения и вызвали Записать(Истина), платформа удалит старую запись (по исходному ключу) и создаст новую. Если же вызвать Записать(Ложь), старая запись сохранится, а новая добавится рядом (при условии уникальности нового ключа).

Особенности работы с транзакциями и безопасная проверка

Важно помнить об архитектурном ограничении платформы 1С: ошибка нарушения первичного ключа СУБД переводит текущую транзакцию в невалидное состояние. Если метод Записать(Ложь) завершился ошибкой внутри открытой транзакции, перехват через Попытка ... Исключение не спасет транзакцию — при попытке вызвать ЗафиксироватьТранзакцию() возникнет ошибка «Транзакция отменена».

Поэтому для проверки наличия записи в транзакционных операциях следует использовать предварительное чтение или запрос:


// Безопасная проверка наличия записи через менеджер
Менеджер = РегистрыСведений.СтатусПаллетоМест.СоздатьМенеджерЗаписи();
Менеджер.Период = ТекущаяДата();
Менеджер.Сектор = Сектор;
Менеджер.Ряд = Ряд;
Менеджер.Паллет = Паллет;
Менеджер.Прочитать();

Если Менеджер.Выбран() Тогда
    // Запись уже существует, выполняем альтернативное действие
    ВызватьИсключение "Запись на текущий период уже существует в базе!";
Иначе
    Менеджер.Ответственный = Ответственный;
    Менеджер.Заблокировано = Ложь;
    Менеджер.Записать(Ложь);
КонецЕсли;

Различия в поведении НабораЗаписей и МенеджераЗаписи

Объект РегистрСведенийМенеджерЗаписи применим исключительно к независимым регистрам сведений и работает только с одной строкой. Для подчиненных регистратору регистров, а также для пакетной обработки данных используется РегистрСведенийНаборЗаписей.

В наборе записей параметр Замещать работает следующим образом:

  1. Записать(Истина). Перед записью новых строк набор полностью удаляет из базы данных все существующие записи, попадающие под установленный отбор (например, по регистратору или измерениям).
  2. Записать(Ложь). Предварительное удаление записей по отбору не выполняется. Новые строки набора физически дописываются в таблицу базы данных к уже существующим записям (при отсутствии коллизий по первичным ключам).

// Добавление строк в регистр сведений без удаления существующих записей регистратора
Набор = РегистрыСведений.ДвиженияТоваров.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ДокументСсылка);

НоваяСтрока = Набор.Добавить();
НоваяСтрока.Период = ТекущаяДата();
НоваяСтрока.Номенклатура = СсылкаНоменклатура;
НоваяСтрока.Количество = 10;

// Запись дописывает строку без предварительной очистки движений по данному документу
Набор.Записать(Ложь);

Использование МенеджерЗаписи в цикле является неоптимальным подходом, так как генерирует отдельные обращения к СУБД для каждой строки. Для массового добавления или обновления информации всегда используйте РегистрСведенийНаборЗаписей с подготовленным массивом данных.

← На главную