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