При разработке в среде 1С:Предприятие 8 программисты часто сталкиваются с задачей программной записи данных в регистры сведений (РС) в момент проведения документов. Однако нередко возникает ситуация: код выполняется без ошибок, отладчик показывает успешное заполнение свойств, но при открытии формы списка регистра новые записи не отображаются. Выясним, почему это происходит, детально разберем типичные ошибки программирования при работе с объектом РегистрСведенийНаборЗаписей и рассмотрим архитектурные нюансы платформы.
Самая частая причина «невидимости» новых записей в интерфейсе сразу после их добавления — это особенности работы транзакций СУБД и механизмов отображения данных в 1С. Если вы выполняете запись в регистр сведений внутри обработчика проведения документа (процедура ОбработкаПроведения в модуле объекта), вся эта операция происходит в рамках одной транзакции базы данных.
Рассмотрим подробнее, как это влияет на видимость записей:
Элементы.Список.Обновить().Проанализируем типичные ошибки в исходном коде, которые часто допускают начинающие разработчики при работе с метаданными. Посмотрим на некорректный фрагмент кода, где выполняется попытка перезаписи данных:
Если НовыйНаборЗаписей.Количество() = 0 Тогда
// Заполнение и добавление новых записей...
КонецЕсли;
Иначе
НовыйНаборЗаписей.Прочитать();
НовыйНаборЗаписей.Очистить();
// Попытка перезаписи...
КонецЕсли;
Разберем по шагам, почему этот код работает не так, как ожидается:
СоздатьНаборЗаписей() создает пустой объект в оперативной памяти. Сразу после этого вызов НовыйНаборЗаписей.Количество() всегда вернет 0. Платформа не обращается к СУБД автоматически. Чтобы узнать, есть ли уже записи в базе данных по данному отбору, необходимо предварительно вызвать метод НовыйНаборЗаписей.Прочитать().Записать() для набора записей по умолчанию принимает параметр замещения: Записать(Истина). Это означает, что при записи набора система автоматически очистит в базе данных все старые записи, соответствующие установленному отбору, и запишет новые. Читать данные методом Прочитать() и затем принудительно вызывать Очистить() абсолютно не требуется — это создает лишнюю бесполезную нагрузку на сервер СУБД.Запись = НоваяЗаписьНабора[0] внутри цикла заполнения приведет к тому, что вы будете постоянно перезаписывать одну и ту же первую строку набора, вместо добавления новых строк. Для добавления новой записи всегда следует использовать метод Добавить().Записать() у конкретной строки набора (например, НоваяЗаписьНабора.Записать()). Важно помнить: объект типа РегистрСведенийЗапись не имеет метода Записать(). Метод Записать() есть только у объекта РегистрСведенийНаборЗаписей или у РегистрСведенийМенеджерЗаписи.Рассмотрим правильный и лаконичный вариант заполнения и сохранения набора записей в независимом регистре сведений при проведении документа. Этот шаблон гарантирует корректную очистку старых движений по данному документу и запись новых актуальных данных:
// 1. Создаем объект набора записей
НовыйНаборЗаписей = РегистрыСведений.ЗначенияПоказателейСхемМотивации.СоздатьНаборЗаписей();
// 2. Устанавливаем жесткий отбор по измерению-ссылке
НовыйНаборЗаписей.Отбор.pzСсылкаТабельПремий.Установить(Ссылка);
// 3. Заполняем набор в цикле по данным табличной части документа
Для Каждого СтрокаТЧ Из ТабельСотрудников Цикл
// Метод Добавить() создает новую строку в наборе записей
НоваяЗапись = НовыйНаборЗаписей.Добавить();
// Заполняем ключевые измерения и ресурсы
НоваяЗапись.ПериодДействия = Дата;
НоваяЗапись.Организация = Организация;
НоваяЗапись.Подразделение = Подразделение;
НоваяЗапись.Показатель = Показатель;
// Поле отбора заполняется автоматически, но для надежности укажем его явно
НоваяЗапись.pzСсылкаТабельПремий = Ссылка;
// Расчет числового показателя
Колво = 0;
Для Сч = 1 По 31 Цикл
Если СтрокаТЧ["Начислить" + Строка(Сч)] = Истина Тогда
Колво = Колво + 1;
КонецЕсли;
КонецЦикла;
НоваяЗапись.Сотрудник = СтрокаТЧ.Сотрудник;
НоваяЗапись.Значение = Колво;
КонецЦикла;
// 4. Записываем весь набор с замещением (старые записи по этому документу затрутся)
НовыйНаборЗаписей.Записать(Истина);
Если вы проектируете архитектуру базы данных и решили использовать независимый регистр сведений для хранения данных, связанных с документами (например, через измерение типа ДокументСсылка.ТабельУчетаРабочегоВремени), вы сталкиваетесь с серьезным архитектурным риском.
Поскольку регистр является независимым, платформа 1С на системном уровне не отслеживает связи между ним и документами-регистраторами. Это порождает следующие проблемы:
<Объект не найден>.... Это приводит к некорректным результатам в отчетах, нарушению логики работы запросов и раздуванию базы данных ненужным мусором.Существует два пути решения этой проблемы:
ПередЗаписью и ПередУдалением:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Если документ помечается на удаление или распроводится - очищаем записи в РС
Если ПометкаУдаления Или РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
НаборЗаписей = РегистрыСведений.ЗначенияПоказателейСхемМотивации.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.pzСсылкаТабельПремий.Установить(Ссылка);
// Записываем пустой набор, тем самым удаляя старые записи из базы
НаборЗаписей.Записать(Истина);
КонецЕсли;
КонецПроцедуры
Процедура ПередУдалением(Отказ)
// При физическом удалении документа обязательно очищаем записи в РС
НаборЗаписей = РегистрыСведений.ЗначенияПоказателейСхемМотивации.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.pzСсылкаТабельПремий.Установить(Ссылка);
НаборЗаписей.Записать(Истина);
КонецПроцедуры
Используя приведенные рекомендации, вы убережете базу данных от появления некорректных связей, повысите быстродействие системы и обеспечите стабильную запись и отображение информации в регистрах сведений 1С.