Как программно изменить записи в регистре сведений 1С после их получения запросом?

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

Часто перед разработчиком 1С встает задача: сначала нужно выбрать определенные записи из регистра сведений по сложным условиям с помощью запроса, а затем внести в них изменения. Сам по себе запрос только читает данные, но не модифицирует их. В этой статье мы подробно разберем, какие стандартные и надежные механизмы платформы 1С существуют для изменения записей регистра сведений, и какой из них выбрать в вашей ситуации.

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

Способ 1: Использование "Менеджера записи" — самый безопасный подход

Этот метод является предпочтительным и наиболее безопасным для изменения одной конкретной записи. Его логика основана на принципе "Прочитать-Изменить-Записать", что гарантирует целостность данных и предотвращает случайное создание дублей. Он идеально подходит, когда вам нужно изменить одну запись, ключ которой вам точно известен.

Рассмотрим по шагам, как работать с менеджером записи:

  1. Создание менеджера. Сначала мы получаем объект менеджера для нужного нам регистра сведений с помощью метода СоздатьМенеджерЗаписи().
  2. Заполнение ключевых полей. Далее необходимо заполнить значения измерений (и поля Период для периодических регистров), которые однозначно идентифицируют запись в регистре. Это "адрес" той записи, которую мы хотим изменить.
  3. Чтение данных. Вызываем метод Прочитать(). В этот момент менеджер обращается к базе данных и пытается найти запись по указанным ключам. Если находит, то загружает в свои свойства значения ее ресурсов и реквизитов.
  4. Проверка существования записи. Перед изменением крайне важно убедиться, что запись действительно была найдена. Для этого используется метод Выбран(), который вернет Истина, если чтение прошло успешно.
  5. Изменение полей. Если запись найдена, мы можем изменять значения ее ресурсов или реквизитов, просто присваивая новые значения соответствующим свойствам менеджера.
  6. Запись изменений. В завершение вызываем метод Записать(). Этот метод сохранит все сделанные нами изменения в базу данных. Если запись с указанными ключами уже существовала, она будет обновлена. Если такой записи не было, будет создана новая.

Посмотрим на практический пример. Допустим, нам нужно изменить цену для конкретного товара и типа цен на текущую дату в периодическом регистре сведений "Цены номенклатуры".


// Получаем ссылки на элементы справочников
СсылкаНаТовар = Справочники.Номенклатура.НайтиПоКоду("000123");
СсылкаНаТипЦен = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Оптовая");
НоваяЦена = 1500;

// 1. Создаем менеджер записи
МенеджерЗаписи = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();

// 2. Заполняем ключевые поля для идентификации записи
МенеджерЗаписи.Номенклатура = СсылкаНаТовар;
МенеджерЗаписи.ТипЦен = СсылкаНаТипЦен;
МенеджерЗаписи.Период = ТекущаяДата();

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

// 4. Проверяем, была ли найдена запись
Если МенеджерЗаписи.Выбран() Тогда
    // 5. Запись найдена, меняем значение ресурса "Цена"
    МенеджерЗаписи.Цена = НоваяЦена;
    
    // 6. Записываем изменения обратно в базу
    МенеджерЗаписи.Записать();
    
    Сообщить("Цена успешно обновлена!");
Иначе
    Сообщить("Запись для указанного товара и типа цен не найдена.");
КонецЕсли;

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

Способ 2: Использование "Набора записей" — для массовых изменений по отбору

Когда требуется изменить не одну, а сразу несколько записей, объединенных общим признаком (например, все цены для одного поставщика или все настройки для одного пользователя), на помощь приходит объект РегистрСведенийНаборЗаписей. Он позволяет работать с группой записей как с единым целым.

Важный момент: отбор в наборе записей работает только по точному равенству. Вы не можете установить отбор типа "больше", "меньше" или "В списке". Отбор устанавливается по значениям одного или нескольких измерений.

Рассмотрим алгоритм работы с набором записей:

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

Посмотрим на пример. Увеличим все цены конкретного поставщика на 10%.


// Получаем ссылку на нужного поставщика
СсылкаНаПоставщика = Справочники.Контрагенты.НайтиПоНаименованию("ООО Поставщик");

// 1. Создаем набор записей
НаборЗаписей = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();

// 2. Устанавливаем отбор по измерению "Поставщик"
НаборЗаписей.Отбор.Поставщик.Установить(СсылкаНаПоставщика);

// 3. Считываем все записи, соответствующие отбору
НаборЗаписей.Прочитать();

// 4. Перебираем записи в наборе и изменяем их
Для Каждого Запись Из НаборЗаписей Цикл
    // Увеличиваем цену на 10%
    Запись.Цена = Запись.Цена * 1.10;
КонецЦикла;

// 5. Записываем весь измененный набор обратно в базу
НаборЗаписей.Записать();

Сообщить("Цены для поставщика " + СсылкаНаПоставщика + " успешно обновлены.");

Способ 3: Обработка результата запроса — гибкость и контроль

Что делать, если условия отбора записей сложные и их невозможно задать через простой отбор набора записей? Например, нужно изменить записи, у которых значение одного ресурса больше определенного числа, или выбрать данные с соединением нескольких таблиц. В этом случае идеальным решением будет комбинация Запроса и Менеджера записи.

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

Именно этот способ был в итоге применен автором вопроса на форуме с помощью инструмента "Консоль запросов".

Алгоритм действий следующий:

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

Рассмотрим пример. Допустим, нам нужно обнулить остатки в регистре сведений "ОстаткиТоваровНаСкладах" для всех товаров из группы "Уцененные товары", у которых текущий остаток меньше 5 штук.


// 1. Составляем запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ОстаткиТоваровНаСкладах.Склад,
    |   ОстаткиТоваровНаСкладах.Номенклатура
    |ИЗ
    |   РегистрСведений.ОстаткиТоваровНаСкладах КАК ОстаткиТоваровНаСкладах
    |ГДЕ
    |   ОстаткиТоваровНаСкладах.Номенклатура.Родитель = &ГруппаНоменклатуры
    |   И ОстаткиТоваровНаСкладах.Остаток < &МинимальныйОстаток";

// Находим нужную группу номенклатуры
ГруппаУценки = Справочники.Номенклатура.НайтиПоНаименованию("Уцененные товары");
Запрос.УстановитьПараметр("ГруппаНоменклатуры", ГруппаУценки);
Запрос.УстановитьПараметр("МинимальныйОстаток", 5);

// 2. Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

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

Сообщить("Обработка остатков завершена.");

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

Что еще важно учитывать?

Выбирайте метод, который наиболее точно соответствует вашей задаче, и всегда тестируйте свои обработки на копии базы данных перед запуском на рабочей.

← На главную