Перейти к содержимому

6.15 Как повлияет удаление элемента справочника и создание нового с такими же реквизитами?

Опубликовано: Обновлено:

Telegram → Просто о платформе 1С

❓ 6.15 Как повлияет удаление элемента справочника, который уже используется в других объектах, а потом создать новый с такими же реквизитами, на поведение программы?


Как уже разбирали в посте 6.14, в платформе следует разделять объектные и необъектные данные.

Элементы справочников, документы, планов видов характеристик и т.д. относятся к объектным данным. Каждый такой объект идентифицируется ссылкой.

Записи регистров относятся к необъектным данным. У них нет аналогичной объектной ссылки: запись определяется значениями ключевых полей.

Данные справочника хранятся в таблицах базы данных. При этом элемент справочника включает не только запись основной таблицы, но и относящиеся к нему табличные части.

В основной таблице есть поле Ссылка, значение которого однозначно идентифицирует элемент.

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

Ссылка содержит внутренний идентификатор объекта.

Уникальный идентификатор можно получить отдельно:

Идентификатор = КонтрагентСсылка.УникальныйИдентификатор();

При этом СправочникСсылка.Контрагенты и УникальныйИдентификатор — разные типы встроенного языка.

В интерфейсе вместо внутреннего идентификатора пользователь видит представление ссылки, например наименование контрагента.

Получается, что в реквизите формы хранится ссылочное значение, а пользователю показывается понятный текст:

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

Поэтому два элемента могут иметь одинаковое наименование, но разные ссылки.

Для работы со справочником во встроенном языке существуют два основных типа:

  • СправочникСсылка.<ИмяСправочника>;
  • СправочникОбъект.<ИмяСправочника>.

Для каждого справочника платформа создаёт собственные типы. Например, СправочникСсылка.Контрагенты и СправочникСсылка.Номенклатура — разные типы.

СправочникСсылка хранит ссылку, идентифицирующую элемент в базе данных. Это значение используется в реквизитах, выбирается в поле ввода, передаётся в параметры запроса.

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

Чтобы изменить существующего контрагента, получим объект по ссылке:

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

Изменяется существующий элемент. Его ссылка сохраняется, поэтому документы продолжают ссылаться на него.

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

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

Объект1 = КонтрагентСсылка.ПолучитьОбъект();
Объект2 = КонтрагентСсылка.ПолучитьОбъект();
СсылкиРавны = Объект1.Ссылка = Объект2.Ссылка; // Истина
ОбъектыРавны = Объект1 = Объект2; // Ложь

Если же присвоить существующий объект другой переменной, обе переменные будут содержать один объект:

Объект3 = Объект1;
ОбъектыРавны = Объект1 = Объект3; // Истина

Один элемент базы данных и один объект встроенного языка — не одно и то же.

И СправочникСсылка, и СправочникОбъект предоставляют доступ к реквизитам через свойства, но данные получают по-разному.

ОбращениеОткуда берётся значение
КонтрагентОбъект.НаименованиеИз данных объекта встроенного языка, находящихся в оперативной памяти
КонтрагентСсылка.НаименованиеИз данных объекта с использованием кэша платформы; при необходимости выполняется чтение из базы

У СправочникОбъект свойства заполняются при чтении существующего элемента. У нового объекта они первоначально получают значения по умолчанию.

Само присваивание нового значения свойству объекта ещё не записывает его в базу. Для сохранения изменений вызывается Записать().

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

Чтобы не считывать объект из базы при каждом обращении через ссылку, платформа использует кэш.

При рассмотрении кэша важно разделять два вопроса:

Что различаемВарианты
В каком контексте читаются данныеОбычный кэш и транзакционный кэш
Какие данные нужныДанные для представления ссылки или полные данные объекта

Получение представления ссылки и чтение произвольного реквизита — разные операции. Наличие данных для отображения представления ещё не означает, что загружен весь объект.

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

Упрощённо чтение выглядит так:

Что запрашиваемЧто есть в кэшеДействие платформы
Представление ссылкиДостаточно данных для представленияСформировать представление по данным кэша
Представление ссылкиНет необходимых данныхПрочитать данные для представления из базы и сохранить в кэше
Значение реквизита через ссылкуТолько данные для представления либо данных нетПрочитать объект целиком, заполнить кэш и вернуть реквизит
Значение реквизита через ссылкуПолные данные объектаВернуть реквизит из кэша

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

Например:

Наименование = КонтрагентСсылка.Наименование;
ИНН = КонтрагентСсылка.ИНН;

Если данных в кэше нет, первое обращение загружает объект. Следующее обращение может получить ИНН из уже загруженных данных.

Но это не означает, что после первого чтения обращений к базе больше не будет: данные могут быть вытеснены из кэша или потребовать проверки актуальности.

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

  • данные удерживаются в кэше около 20 минут, при этом есть ограничение на количество хранимых объектов;
  • после интервала 20 секунд при очередном обращении проверяется, менялся ли объект в базе;
  • если объект изменился, данные кэша обновляются;
  • при записи объекта в этом же сеансе его данные обновляются в кэше.

Транзакционный кэш используется отдельно при обращениях внутри транзакции. Это обеспечивает получение актуальных данных объекта при обращении к его реквизитам через ссылку в рамках транзакции.

Кэш сокращает повторные чтения

Для получения одного-двух реквизитов загрузка объекта вместе со всеми табличными частями может оказаться избыточной.

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

В конфигурациях с БСП для этого есть функции общего модуля ОбщегоНазначения:

  • ЗначениеРеквизитаОбъекта() — для одного реквизита;
  • ЗначенияРеквизитовОбъекта() — для нескольких.

Например:

Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
КонтрагентСсылка, "Наименование, ИНН");
Наименование = Реквизиты.Наименование;
ИНН = Реквизиты.ИНН;

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

Это рекомендация по чтению данных, а не запрет на обращение к реквизитам через ссылку.

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

Что изменилосьКак записываются изменения
Реквизиты самого объекта не менялисьЗаписывается минимальная служебная информация об изменении
Табличная часть не меняласьОна не перезаписывается
Изменены отдельные строки или добавлены новыеЗаписываются изменённые и добавленные строки
Строки удалены или изменён их порядокПерезаписываются все строки соответствующей табличной части

Поэтому чтение объекта целиком не означает, что при каждом вызове Записать() платформа обязательно перезаписывает все его данные.

Что происходит при удалении и создании заново

Заголовок раздела «Что происходит при удалении и создании заново»

Теперь вернёмся к исходной ситуации.

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

При обычном создании нового элемента ему назначается новая ссылка. Повторение кода, наименования, ИНН и других реквизитов не возвращает ссылку удалённого элемента.

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

Заголовок раздела «Существующие документы продолжают хранить ссылку на удалённый элемент. Создание нового элемента с такими же реквизитами автоматически эту ссылку не заменяет.»

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