Экземпляр объекта в 1С: от создания в памяти до записи в базу

· 9 мин

Содержание

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

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

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

Что скрывается за словом «экземпляр»

В обычном коде вы постоянно создаёте экземпляры, даже не называя их так. Каждая строка с оператором Новый порождает новый экземпляр:

Параметры = Новый Структура;
Параметры.Вставить("Организация", ВыбраннаяОрганизация);

ТоварыНаСкладе = Новый ТаблицаЗначений;
Запрос = Новый Запрос;

Здесь Параметры, ТоварыНаСкладе и Запрос — три разных экземпляра трёх разных типов. У каждого своё содержимое и свой участок памяти. Если следом написать ВторыеПараметры = Новый Структура, появится ещё один, независимый экземпляр Структуры — заполнять и менять его можно отдельно от первого.

Важная деталь: присваивание само по себе новый экземпляр не создаёт.

А = Новый Массив;   // создан экземпляр массива
Б = А;              // Б указывает на ТОТ ЖЕ экземпляр
Б.Добавить("строка");
Сообщить(А.Количество()); // выведет 1 — массив один на двоих

Переменные А и Б ссылаются на один объект в памяти. Это поведение называют ссылочной семантикой, и для большинства объектных типов 1С оно работает именно так. Примитивные значения (число, строка, булево, дата) ведут себя иначе — они копируются при присваивании.

Чем экземпляр отличается от типа и объекта метаданных

Три понятия легко путаются, поэтому разложим их по полочкам.

  • 🧩 Тип — это вид значения: Строка, Число, Массив, СправочникСсылка.Контрагенты. Тип отвечает на вопрос «что это вообще за данные и какие у них свойства и методы».
  • 📐 Объект метаданных — элемент дерева конфигурации: конкретный справочник, документ, регистр. Его вы видите в Конфигураторе слева в дереве. Объект метаданных описывает структуру: реквизиты, табличные части, формы.
  • 📦 Экземпляр — одно конкретное значение этого типа в памяти в момент выполнения кода.

Аналогия из жизни. Объект метаданных «Справочник Номенклатура» — это бланк карточки товара с полями «Наименование», «Единица», «Ставка НДС». Тип СправочникОбъект.Номенклатура — описание того, как с заполненной карточкой работать. А экземпляр — конкретная заполненная карточка «Болт М6», которую вы держите в руках.

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

Для встроенных типов (Структура, Соответствие, Запрос) объекта метаданных нет вообще — их описывает сама платформа. Но экземпляры у них такие же: Новый Соответствие — это экземпляр.

Как создаётся экземпляр объекта в 1С

Способов несколько, и выбор зависит от того, что именно вы создаёте.

1. Оператор Новый — для встроенных типов. Самый частый случай. Подходит для коллекций, запросов, построителей:

Список = Новый СписокЗначений;
Соответствие = Новый Соответствие;
ДатаДокумента = Новый Структура("Начало, Конец");

2. Динамическое создание через Новый(Тип(...)). Когда имя типа известно только в момент выполнения — например, пришло строкой из настройки:

ИмяТипа = "Массив";
Коллекция = Новый(Тип(ИмяТипа));

3. Методы менеджера — для прикладных объектов. Новый элемент справочника, документ или группу создаёт соответствующий менеджер:

НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Наименование = "Болт М6";
НовыйТовар.Записать();

НовыйЗаказ = Документы.ЗаказПокупателя.СоздатьДокумент();

До вызова Записать() экземпляр живёт только в памяти — в базе данных его ещё нет. Проверить это можно методом ЭтоНовый():

Если НовыйТовар.ЭтоНовый() Тогда
    // элемент ещё не сохранён
КонецЕсли;

4. Получение объекта из ссылки — ПолучитьОбъект(). Когда элемент уже есть в базе и вы хотите его изменить:

ОбъектТовара = СсылкаНаТовар.ПолучитьОбъект();
ОбъектТовара.Комментарий = "Проверено";
ОбъектТовара.Записать();

Этот способ особый, и о нём — отдельный разговор ниже.

Ссылка и объект: два лица одного элемента

Это ключевое место, на котором спотыкаются почти все, кто приходит в 1С из других языков. Один и тот же элемент справочника существует в двух разных представлениях.

  • 🔗 Ссылка (СправочникСсылка.Номенклатура) — лёгкий неизменяемый указатель на запись в базе. По ссылке можно прочитать реквизиты, подставить её в другой документ, сравнить с другой ссылкой. Но изменить данные через ссылку нельзя.
  • 📝 Объект (СправочникОбъект.Номенклатура) — «тяжёлое» представление. Это полностью загруженный в память экземпляр со всеми реквизитами и табличными частями. Его можно менять и записывать.

Ссылка превращается в объект вызовом ПолучитьОбъект(). Обратно — через свойство Ссылка объекта.

// есть ссылка, нужно поменять поле
Объект = Ссылка.ПолучитьОбъект();  // загрузили тяжёлый экземпляр
Объект.Комментарий = "Изменено";
Объект.Записать();                 // сохранили в базу

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

Попытка присвоить значение реквизиту прямо через ссылку (Ссылка.Комментарий = "...") приведёт к ошибке: у ссылки нет изменяемых реквизитов. Сначала ПолучитьОбъект(), потом изменение.

Когда что брать — короткая подсказка:

Ссылка или объект — что использовать?

Жизненный цикл экземпляра: от создания до выгрузки

Экземпляр проходит несколько стадий, и понимание этих стадий убирает большинство «мистических» ошибок.

  1. Создание. В памяти выделяется место, вызывается оператор Новый или метод менеджера. Экземпляр готов к работе.
  2. Заполнение и использование. Вы присваиваете реквизиты, вызываете методы, передаёте экземпляр в процедуры. Всё это время он живёт в памяти.
  3. Фиксация (для прикладных объектов). Вызов Записать() переносит состояние экземпляра в базу данных. Без этого вызова все изменения останутся только в памяти и пропадут.
  4. Освобождение. Когда на экземпляр не остаётся ни одной ссылки, платформа убирает его из памяти.

Последний пункт стоит пояснить. Память под объекты в 1С освобождается автоматически, по подсчёту ссылок: как только последняя переменная, указывавшая на экземпляр, вышла из области видимости или получила другое значение, объект уничтожается.

Процедура Посчитать()
    Запрос = Новый Запрос;  // экземпляр создан
    // ... работа с запросом ...
КонецПроцедуры               // процедура завершилась — Запрос освобождён

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

БольшаяТаблица = Выгрузка();
// ... использовали таблицу ...
БольшаяТаблица = Неопределено;  // память освободится сразу

Циклические ссылки (объект А держит объект Б, а Б держит А) подсчёт ссылок распутывает хуже. Если в длительном фоновом задании память растёт, проверьте, не замкнулись ли ваши структуры сами на себя.

ООП в 1С: что от него есть, а чего нет

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

Что есть:

  • ✅ Инкапсуляция. У прикладных объектов есть свойства и методы. Поведение элемента справочника описывается в его модуле объекта — обработчики ПередЗаписью, ПриЗаписи, ОбработкаПроведения. Данные и логика лежат рядом.
  • ✅ Экземпляры по типу. Как мы и разбираем: тип один, экземпляров много.

Чего нет:

  • ❌ Пользовательских классов. Вы не можете во встроенном языке объявить свой класс со своими полями и методами, как в C# или Python. Набор типов задаёт платформа и дерево метаданных.
  • ❌ Классического наследования. Один справочник не наследует реквизиты и методы другого. Ближайший по духу механизм — расширения конфигурации (появились в платформе 8.3.6): они позволяют добавлять свойства и переопределять поведение существующих объектов, не меняя исходную конфигурацию. Но это не наследование классов в привычном смысле.
  • ❌ Полиморфизма через иерархию классов. Общий код для разных объектов обычно пишут в общих модулях и передают туда ссылки, а не строят цепочки классов.

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

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

Собрал ситуации, которые чаще всего всплывают в логах и на этапе отладки.

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

Данные = НайтиЗначение(); // вернуло Неопределено
Сообщить(Данные.Наименование); // ошибка: у Неопределено нет реквизитов

Лечится проверкой перед обращением: Если Данные <> Неопределено Тогда ....

Изменение через ссылку вместо объекта. Попытка Ссылка.Реквизит = Значение не компилируется или падает — ссылка неизменяема. Нужно ПолучитьОбъект().

Забыли Записать(). Изменили реквизиты объекта, но не вызвали запись. В памяти всё поменялось, а в базе — нет. После перезапуска изменений не видно, потому что их там и не было.

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

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

Как не перегружать память экземплярами

Экземпляры прикладных объектов тяжёлые: вместе с ними в память загружаются все реквизиты и табличные части. На больших объёмах это заметно.

  • 📉 Читайте запросом, а не объектом. Если нужны наименование и артикул тысячи товаров, не вызывайте ПолучитьОбъект() в цикле. Один запрос вернёт нужные поля в разы быстрее и без загрузки полных экземпляров.
  • 🧹 Освобождайте тяжёлые экземпляры. Большую таблицу значений или выгрузку после использования присвойте Неопределено, если до конца процедуры ещё далеко.
  • 🔁 Не создавайте одно и то же в цикле. Экземпляр Запроса или Структуры-шаблона, который не меняется от итерации к итерации, создавайте один раз до цикла.
  • 📦 Обрабатывайте порциями. Если нужно перебрать и изменить десятки тысяч элементов, делите на пакеты и записывайте по частям, а не держите всё в памяти сразу.

Правило простое: объект поднимаем в память только тогда, когда собираемся его менять. Для всего остального хватает ссылки и запроса.

Частые вопросы

«Экземпляр объекта» и «объект» — это одно и то же?
В разговорной речи часто да. Но строго: «объект метаданных» — это элемент конфигурации (справочник, документ), а «экземпляр» — конкретное значение в памяти во время работы. Один объект метаданных порождает множество экземпляров.
Почему при присваивании двух переменных меняются обе?
Потому что обе указывают на один экземпляр в памяти — у объектных типов ссылочная семантика. Чтобы получить независимую копию коллекции, используйте методы копирования (например, у таблицы значений — Скопировать()), а не простое присваивание.
Как узнать, записан ли уже элемент в базу?
У объекта есть метод ЭтоНовый(). Он возвращает Истина, пока экземпляр создан в памяти, но ещё не сохранён вызовом Записать().
Чем отличается `Новый` от `СоздатьЭлемент()`?
Новый создаёт экземпляр встроенного типа (коллекцию, запрос). СоздатьЭлемент() — метод менеджера справочника, он создаёт новый экземпляр прикладного объекта, готовый к заполнению и записи в базу.
Можно ли в 1С создать свой класс с нужными методами?
Собственный класс во встроенном языке объявить нельзя — набор типов задаёт платформа и метаданные. Расширить поведение существующих объектов помогают расширения конфигурации и общие модули, но это не классы в смысле C# или Java.