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

Справочники и Данные · 12 мин

Как записать данные в справочник 1С программно

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

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

Во встроенном языке 1С работа со справочником ведётся через менеджер справочника Справочники.ИмяСправочника. Основные методы — СоздатьЭлемент(), СоздатьГруппу(), НайтиПоКоду(), НайтиПоНаименованию() и НайтиПоРеквизиту(). После заполнения реквизитов объект фиксируется в базе методом Записать().

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

Как устроена программная работа со справочником

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

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

Если справочник иерархический, элементы делятся на группы (папки) и обычные элементы. Группа создаётся методом СоздатьГруппу(), а принадлежность элемента к группе задаётся реквизитом Родитель. Если справочник подчинён другому (например, «ЕдиницыИзмерения» подчинены «Номенклатуре»), обязательным становится реквизит Владелец — без него запись завершится ошибкой.

Создание и запись нового элемента

Базовый сценарий создания элемента выглядит так: получаем новый объект, заполняем наименование и реквизиты, записываем. Минимальный пример для справочника «Номенклатура»:

НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();

НовыйЭлемент.Наименование = "Кабель ВВГ 3х2,5";

НовыйЭлемент.Артикул = "КБ-325";

НовыйЭлемент.Записать();

Сообщить("Создан элемент: " + НовыйЭлемент.Ссылка);

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

Группа = Справочники.Номенклатура.НайтиПоНаименованию("Кабельная продукция");

НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();

НовыйЭлемент.Родитель = Группа;

НовыйЭлемент.Наименование = "Кабель ВВГ 3х2,5";

НовыйЭлемент.Записать();

Реквизиты ссылочного типа заполняются ссылками на элементы других справочников, а не строками. Например, НовыйЭлемент.Валюта = Справочники.Валюты.НайтиПоКоду("643"). Передача строки вместо ссылки вызовет ошибку преобразования типа либо запишет пустое значение — зависит от настроек реквизита.

Порядок создания элемента
  1. 1
    Получите объект: Справочники.ИмяСправочника.СоздатьЭлемент()
  2. 2
    Заполните Наименование и обязательные реквизиты (Родитель, Владелец при необходимости)
  3. 3
    Заполните табличные части через Добавить(), если они есть
  4. 4
    Вызовите Записать() и проверьте, что свойство Ссылка заполнено
  5. 5
    При массовой загрузке оберните запись в транзакцию и обработайте исключения

Создание группы и работа с иерархией

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

НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();

НоваяГруппа.Наименование = "Электротовары";

НоваяГруппа.Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Товары");

НоваяГруппа.Записать();

Обратите внимание на тип иерархии, заданный в конфигураторе. Если у справочника иерархия «элементов», то группа может содержать только элементы, а другие группы — нет. Если иерархия «групп и элементов», вложенность групп не ограничена. Несоответствие типа иерархии — частая причина ошибки «Неверный родитель» при записи.

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

Поиск перед записью и защита от дублей

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

ЭлементСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7707083893");

Если ЭлементСсылка.Пустая() Тогда

НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();

НовыйЭлемент.Наименование = "ООО Ромашка";

НовыйЭлемент.ИНН = "7707083893";

НовыйЭлемент.Записать();

Иначе

Сообщить("Контрагент уже существует: " + ЭлементСсылка);

КонецЕсли;

Метод НайтиПоНаименованию() ищет точное совпадение и не защищает от дублей вида «ООО Ромашка» и «ООО "Ромашка"». Для надёжной идентификации используйте реквизиты с формальной уникальностью: ИНН+КПП для контрагентов, штрихкод или артикул для товаров. Если таких реквизитов нет, добавьте служебный реквизит «ВнешнийИдентификатор» при доработке конфигурации.

Если элемент найден, но его данные устарели, не создавайте новый — получите объект через ЭлементСсылка.ПолучитьОбъект(), обновите реквизиты и запишите. Такой подход «найти-или-обновить» стандартен для обменов с внешними системами.

Типичные ошибки
01
Создание элемента без предварительного поиска — при повторном запуске обработки появляются дубли
02
Поиск только по наименованию — элементы с кавычками или лишними пробелами считаются разными
03
Запись элемента без заполнения Владелец в подчинённом справочнике — ошибка записи
04
Присвоение строки реквизиту ссылочного типа вместо ссылки — ошибка преобразования или пустое значение
05
Вызов ПолучитьОбъект() в цикле для тысяч элементов без необходимости — резкое падение производительности

Заполнение табличных частей и особые режимы записи

Если у справочника есть табличные части (например, «КонтактнаяИнформация» в типовых конфигурациях), они заполняются через метод Добавить() до вызова Записать():

НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();

НовыйЭлемент.Наименование = "ООО Ромашка";

СтрокаКИ = НовыйЭлемент.КонтактнаяИнформация.Добавить();

СтрокаКИ.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес;

СтрокаКИ.Представление = "г. Москва, ул. Примерная, д. 1";

НовыйЭлемент.Записать();

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

Транзакции, блокировки и массовая загрузка

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

НачатьТранзакцию();

Попытка

Для Каждого СтрокаДанных Из ДанныеЗагрузки Цикл

НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();

НовыйЭлемент.Наименование = СтрокаДанных.Наименование;

НовыйЭлемент.Записать();

КонецЦикла;

ЗафиксироватьТранзакцию();

Исключение

ОтменитьТранзакцию();

Сообщить("Ошибка загрузки: " + ОписаниеОшибки());

КонецПопытки;

В многопользовательском режиме длительные транзакции держат блокировки таблицы справочника и мешают работе других пользователей. Поэтому массовую загрузку лучше выполнять в нерабочее время либо мелкими порциями. Также учитывайте, что при записи срабатывают подписки на события и обработчики ПриЗаписи, заложенные в конфигурации, — они могут изменять данные или отклонять запись по бизнес-правилам.

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

Проверка результата и типичные ошибки записи

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

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

Контрольные точки

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

Свойство Ссылка у объекта после Записать()
Норма

Ссылка заполнена, Пустая() возвращает Ложь

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

Исключение при записи или пустая ссылка

Поиск элемента после загрузки
Норма

НайтиПоНаименованию/НайтиПоРеквизиту возвращает ровно один элемент

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

Найдено несколько элементов с одинаковым ключом — дубли

Открытие элемента в пользовательском режиме
Норма

Элемент открывается, реквизиты и табличные части заполнены

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

Пустые обязательные поля, элемент не отображается в списке из-за отбора по владельцу или пометки удаления

Часто задаваемые вопросы

Чем отличается СоздатьЭлемент() от ПолучитьОбъект()?

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

Как записать элемент, если справочник подчинён другому?

Перед записью обязательно заполните реквизит Владелец ссылкой на элемент справочника-владельца. Например, для единиц измерения: НовыйЭлемент.Владелец = СсылкаНаНоменклатуру. Без владельца запись завершится ошибкой, а сам элемент не будет виден в интерфейсе.

Почему после Записать() элемент не виден в списке справочника?

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

Можно ли записать элемент без проверки обязательных реквизитов?

Да, установив перед записью Объект.ОбменДанными.Загрузка = Истина. Но это отключает и прикладные проверки, поэтому применяйте такой режим только для технических загрузок с гарантированно корректными данными и лучше на копии базы.

Как обновить существующий элемент, а не создать дубль?

Сначала найдите элемент по уникальному признаку — НайтиПоРеквизиту("ИНН", ...) или НайтиПоКоду(). Если ссылка не пустая, вызовите у неё ПолучитьОбъект(), измените нужные реквизиты и выполните Записать(). Создавать новый элемент через СоздатьЭлемент() в этом случае не нужно.

Что делать, если при массовой загрузке возникают конфликты блокировок?

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

Итог

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

Запись в справочник 1С выполняется по схеме: СоздатьЭлемент() — заполнение реквизитов — Записать(). Перед созданием ищите существующий элемент по уникальному реквизиту, для подчинённых и иерархических справочников заполняйте Владелец и Родитель, при массовой загрузке используйте транзакции порциями и обязательно проверяйте результат по заполненной ссылке.