Почему значение измерения с составным типом данных в МенеджереЗаписи регистра сведений становится Неопределено?

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

Работа с регистрами сведений — одна из базовых задач разработчика 1С, но она таит в себе немало нюансов, особенно когда дело касается составных типов данных и использования объекта МенеджерЗаписи. Часто возникает ситуация: вы программно заполняете измерения, отладчик показывает, что переменная содержит данные, но после записи в регистре оказывается пустота или значение Неопределено. Разберем эту ситуацию подробно, выясним причины и рассмотрим правильные подходы к разработке.

Анализ проблемы: почему данные «исчезают»

Рассмотрим типичный сценарий. У нас есть независимый непериодический регистр сведений, где одно из ключевых измерений (например, Документ) имеет составной тип, включающий несколько видов документов. При попытке записи кода, подобного приведенному ниже, разработчик сталкивается с тем, что в базе данных поле остается пустым:


СоздатьЦепочка = РегистрыСведений.Цепочка1.СоздатьМенеджерЗаписи();
    
СоздатьЦепочка.Купаж = Купаж;
СоздатьЦепочка.Документ = Документ; // Ошибка кроется здесь
СоздатьЦепочка.ПартияКупажа = ПартияКупажа;
СоздатьЦепочка.Записать(Истина);

Проанализируем ситуацию: в отладчике переменная Документ может выглядеть как «Купажный акт №...». Однако, если мы проверим тип этой переменной через функцию ТипЗнч(Документ), то увидим, что это не ссылка на документ, а Выборка (например, ДокументВыборка.КупажныйАкт).

В этом и заключается главная ловушка. Объект Выборка — это своего рода «курсор», который указывает на текущую строку в результате запроса или перебора. Система 1С не может записать сам объект выборки в базу данных, так как измерения регистра могут хранить только ссылочные типы, примитивные типы (строка, число, дата, булево) или значения перечислений. При попытке присвоить «курсор» (выборку) измерению, система либо молча очищает значение, либо записывает Неопределено, если тип не совпал.

Решение проблемы: Ссылка против Выборки и Объекта

Чтобы данные корректно сохранились в регистре, мы должны передать именно ссылку на объект. Рассмотрим исправленный вариант кода:


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

Важно помнить: аналогичная ошибка часто возникает и при работе с объектами (ДокументОбъект или СправочникОбъект). Если вы попытаетесь присвоить измерению сам объект, находящийся в оперативной памяти для редактирования, результат будет таким же плачевным. Всегда используйте свойство .Ссылка.

Особенности работы с МенеджеромЗаписи

Разберем подробнее, как работает МенеджерЗаписи. Это объект, предназначенный для работы с одной конкретной записью регистра, определяемой набором ее значений измерений (ключом записи).

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

Составные типы данных и их коварство

Когда мы выбираем для измерения составной тип данных, мы должны учитывать, как это отражается на уровне СУБД (SQL). Рассмотрим технические детали:

Раздувание таблиц и индексов: Для каждой колонки с составным типом SQL-сервер создает несколько служебных полей (для хранения идентификатора типа и самой ссылки). Если в составной тип входит 20 видов документов, это существенно увеличивает размер индекса и замедляет поиск по этому измерению.

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

Альтернатива: Набор записей

Проанализируем ситуацию с точки зрения производительности. Если ваша задача — записать не одну строчку, а целую цепочку документов (как в примере автора темы), использование МенеджераЗаписи в цикле является неоптимальным. Каждый вызов метода Записать() — это отдельное обращение к базе данных и отдельная транзакция.

Рассмотрим более профессиональный подход с использованием объекта РегистрСведенийНаборЗаписей:


Набор = РегистрыСведений.Цепочка1.СоздатьНаборЗаписей();
// Если нужно добавить записи, не затирая старые, используем отбор
Набор.Отбор.Документ.Установить(НужнаяСсылка);

НоваяЗапись = Набор.Добавить();
НоваяЗапись.Купаж = Купаж;
НоваяЗапись.Документ = ДокументСсылка;
// ... заполнение остальных полей

Набор.Записать(); // Записывает все накопленные записи одним пакетом

Использование набора записей позволяет существенно ускорить работу системы и снизить нагрузку на сервер за счет уменьшения количества транзакций.

Выводы и рекомендации

Выясним основные правила, которые помогут избежать ошибок при работе с регистрами:

Соблюдение этих простых правил и понимание разницы между объектами метаданных 1С позволит вам создавать надежные и быстрые механизмы учета.

← На главную