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