К статье
Практический материал

Разработка и Конфигурация · 11 мин

Мутабельные значения в 1С: что это и как с ними работать

Что такое мутабельные значения в 1С, чем они отличаются от примитивных типов, как изменение объекта влияет на данные и каких ошибок избегать при разработке.

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

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

Что такое мутабельность и какие типы в 1С изменяемы

Мутабельность — свойство типа данных. Если тип мутабелен, то операция изменения затрагивает сам объект в памяти, а не создаёт его копию. Если тип иммутабелен, любое «изменение» на самом деле создаёт новое значение, а старое остаётся нетронутым.

В 1С к мутабельным относятся:

  • объекты базы данных: ДокументОбъект, СправочникОбъект, ПланСчетовОбъект и аналогичные;
  • коллекции: Массив, ТаблицаЗначений, ДеревоЗначений, Структура, Соответствие, СписокЗначений;
  • объекты формы: ДанныеФормыСтруктура, ДанныеФормыКоллекция;
  • прочие прикладные объекты: Запрос, ПостроительОтчета, ТабличныйДокумент и т. п.

Иммутабельны примитивные типы: Число, Строка, Дата, Булево, Неопределено, NULL. Например, функция СтрЗаменить() не меняет исходную строку — она возвращает новую. А вот добавление строки в таблицу значений меняет именно существующую таблицу.

Передача по ссылке и по значению: где проявляется мутабельность

Главное практическое следствие мутабельности — поведение при передаче параметров в процедуры и функции. Мутабельные объекты передаются по ссылке: внутри вызванной процедуры работает тот же самый объект. Если процедура добавит строку в переданную таблицу значений, вызывающий код увидит эту строку.

Примитивные типы передаются по значению: процедура получает копию, и её изменения никак не влияют на исходную переменную. Модификатор Знач в объявлении параметра заставляет передать копию, но для сложных объектов его поведение ограничено — например, объекты базы данных через Знач не копируются в полном смысле.

Процедура ДобавитьСтроку(Таблица)

НоваяСтрока = Таблица.Добавить();

НоваяСтрока.Номенклатура = "Товар";

КонецПроцедуры

// После вызова исходная таблица уже содержит строку

ДобавитьСтроку(МояТаблица);

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

Мутабельные объекты базы данных: ДокументОбъект и его жизненный цикл

Объект типа ДокументОбъект или СправочникОбъект — это мутабельное представление данных в памяти. Вы получаете объект через ПолучитьОбъект() по ссылке, меняете реквизиты, добавляете строки в табличные части — и все эти изменения существуют только в памяти до вызова метода Записать().

Это создаёт важное разделение: изменение объекта в памяти не меняет данные в базе. Обратное тоже верно: если два фрагмента кода получили объект одного и того же документа и оба вызвали Записать(), второй может получить ошибку из-за конфликта версий либо молча перезаписать чужие изменения — поведение зависит от режима и блокировок.

Типичный безопасный сценарий: получить объект, изменить, записать, освободить. Опасный сценарий: долго держать объект в памяти, передавать его между вызовами сервера и клиента, записывать после длительных вычислений — за это время данные в базе могли изменить другие пользователи.

Мутабельность в формах: ДанныеФормы и модифицированность

В управляемых формах данные реквизитов — тоже мутабельные объекты. Изменение реквизита формы программно или пользователем приводит к установке признака модифицированности: платформа отслеживает, что состояние формы отличается от сохранённого.

Практические следствия: программное заполнение табличной части в обработчике на сервере тоже «модифицирует» форму, и при закрытии пользователь получит вопрос о сохранении. Если это нежелательно, после программных изменений можно сбросить признак через Модифицированность = Ложь, но делать это нужно осознанно — иначе реальные изменения пользователя могут быть потеряны без предупреждения.

При передаче данных формы между клиентом и сервером платформа сериализует мутабельные структуры. Частые серверные вызовы с передачей больших таблиц заметно замедляют работу, поэтому объёмные изменения лучше выполнять целиком на сервере одним вызовом.

Признак проблемы с мутабельностью в форме — «плавающий» вопрос о сохранении при закрытии, хотя пользователь ничего не менял. Проверьте обработчики ПриСозданииНаСервере и ПриОткрытии: часто там программно изменяются реквизиты формы.
ПЗ
Практическое замечание

Типичные ошибки при работе с мутабельными значениями

Большинство дефектов связано с тем, что разработчик ожидает поведение «по значению» там, где работает ссылка на общий объект. Разберём характерные случаи.

Типичные ошибки
01
Передача таблицы значений в процедуру, которая очищает или фильтрует её, без копии — вызывающий код теряет данные. Решение: передавать Таблица.Скопировать() или документировать, что процедура меняет параметр.
02
Повторное использование одной Структуры как шаблона строки: все строки ссылаются на одну структуру, и изменение одной меняет все. Решение: создавать новую структуру на каждую итерацию.
03
Запись объекта, полученного ранее, после того как данные в базе уже изменил другой сеанс — перезапись чужих изменений. Решение: перечитывать объект перед записью при длительных операциях.
04
Сравнение двух мутабельных объектов оператором «=» с ожиданием сравнения содержимого: сравниваются ссылки, а не содержимое.

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

Как проверить поведение и отладить проблему

Если подозреваете, что данные меняются «сами собой», проверьте цепочку передачи объекта. Основной инструмент — отладчик: поставьте точку останова в месте создания коллекции и отслеживайте, в какие процедуры она передаётся.

Порядок действий
  1. 1
    Найдите место создания объекта (таблицы, структуры, объекта документа) и зафиксируйте его состояние в отладчике.
  2. 2
    Проследите все вызовы, куда объект передаётся параметром, и проверьте, нет ли внутри них изменений.
  3. 3
    Проверьте, не сохраняется ли объект в реквизит формы, переменную модуля или параметр сеанса.
  4. 4
    Если объект менять нельзя — замените передачу на передачу копии и повторите сценарий.
  5. 5
    Проверьте результат: вызывающий код должен видеть исходное состояние коллекции после вызова процедуры.
Контрольные точки

Как проверить результат

Состояние коллекции после вызова процедуры
Норма

Состав и содержимое строк не изменились, если процедура не должна их менять

Тревожный признак

Добавились или удалились строки, изменились значения колонок

Модифицированность формы
Норма

Форма не спрашивает о сохранении, если пользователь ничего не вводил

Тревожный признак

Вопрос о сохранении появляется сразу после открытия

Запись объекта документа
Норма

Запись проходит без ошибок блокировок при параллельной работе

Тревожный признак

Ошибки «Конфликт блокировок» или потеря чужих изменений

Когда выбирать копию, а когда работать по ссылке

Передача по ссылке — нормальный и эффективный механизм, отказываться от него не нужно. Копирование оправдано, когда вызываемый код не должен влиять на вызывающий, когда объект помещается в долгоживущее хранилище или когда обработка выполняется асинхронно.

Маршрут решения

Как выбрать действие

Процедура по смыслу должна заполнить или изменить переданную коллекциюПередавайте объект по ссылке и явно укажите это в имени или комментарии процедуры
Вызываемый код не должен влиять на исходные данныеПередайте копию: Таблица.Скопировать(), новая структура, новый массив
Объект сохраняется в кэш, реквизит формы или фоновое заданиеСохраняйте копию или сериализованное представление, а не живой объект
Работаете с ДокументОбъект при параллельной записиМинимизируйте время между ПолучитьОбъект() и Записать(), используйте транзакции и блокировки
Итог

Что важно запомнить

Мутабельные значения в 1С — объекты, изменяемые по ссылке: документы, справочники, таблицы значений, массивы, структуры. Примитивные типы иммутабельны. Передача в процедуру идёт по ссылке, поэтому изменения видны вызывающему коду; если это нежелательно — передавайте копию. Для объектов базы данных сокращайте интервал между чтением и записью, чтобы избежать конфликтов при параллельной работе.

Частые вопросы о мутабельных значениях в 1С

Чем ссылка на документ отличается от объекта документа?

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

Почему строка в 1С считается иммутабельной?

Строковые функции встроенного языка (СтрЗаменить, Лев, СокрЛП и другие) возвращают новую строку, не меняя исходную. Переменная просто переназначается на новое значение. Поэтому строки безопасно передавать в процедуры — вызывающий код не пострадает.

Как правильно скопировать таблицу значений?

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

Можно ли передать мутабельный объект в фоновое задание?

Напрямую объекты вроде ТаблицаЗначений или ДокументОбъект в фоновое задание не передаются — параметры сериализуются, и поддерживаются ограниченные типы. Обычно передают примитивные данные, ссылки или помещают данные во временное хранилище, а в задание передают адрес хранилища.

Почему сравнение двух одинаковых таблиц даёт Ложь?

Оператор сравнения для объектов коллекций сравнивает ссылки, а не содержимое. Две таблицы с идентичными строками — разные объекты в памяти, поэтому результат — Ложь. Для сравнения содержимого нужно сравнивать колонки и построчно значения, либо сериализовать обе таблицы и сравнить результат.

Опасно ли хранить структуру в реквизите формы?

Сама по себе структура в реквизите формы допустима, но любой код, получивший к ней доступ, может её изменить, что влияет на модифицированность формы и усложняет отладку. Для служебных данных, которые не должны меняться пользователем, надёжнее хранить копию при выдаче наружу либо использовать реквизиты с ограниченным доступом через программный интерфейс формы.