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