Как исправить ошибку IDENTITY_INSERT при записи во внешний источник данных 1С

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

При работе с внешними источниками данных (ВИД) в 1С программисты часто сталкиваются с ситуацией, когда попытка изменить существующую запись в сторонней базе данных (например, MS SQL Server) приводит к критической ошибке: "Невозможно вставить явное значение для столбца идентификаторов в таблице, когда параметр IDENTITY_INSERT имеет значение OFF". Эта проблема особенно актуальна для таблиц, в которых первичный ключ является автоинкрементным полем (Identity).

В этой статье мы подробно разберем, почему возникает эта ошибка, как работает механизм записи 1С во внешних источниках и рассмотрим несколько способов решения этой задачи: от настройки метаданных до выполнения прямых SQL-запросов.

Анализ причины возникновения ошибки

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

Проблема заключается в том, что для необъектных таблиц платформа 1С часто реализует метод Записать() не через команду UPDATE, а через связку DELETE и INSERT. То есть текущая запись удаляется, и на ее место вставляется новая с обновленными данными. Поскольку 1С пытается передать в команду INSERT старое значение ключевого поля (которое в SQL Server помечено как IDENTITY), СУБД блокирует операцию, так как по умолчанию запрещено вручную указывать значения для автоинкрементных столбцов.

Даже если 1С пытается выполнить UPDATE, она может включать поле ключа в секцию SET, что также вызывает недовольство со стороны SQL-сервера.

Решение 1: Использование метода Выполнить() для прямого обновления

Самым надежным и производительным способом решения проблемы является использование механизма прямого выполнения SQL-запросов. Начиная с версии 8.3.10, платформа позволяет отправлять команды внешнему источнику напрямую. Это позволяет нам выполнить классический UPDATE, который не затронет поле IDENTITY.

Рассмотрим пример кода, который заменяет использование менеджера записи на прямой запрос:


// Определяем параметры подключения и текст запроса
ИмяИсточника = "УчетВесовогоМатериала";
ТекстЗапроса = "UPDATE build_main SET ЗагруженоВ1С = 1 WHERE НомерСтроки = " + Формат(СтрокаТЗ.НомерСтроки, "ЧГ=0");

// Выполняем команду напрямую в обход объектной модели 1С
ВнешниеИсточникиДанных[ИмяИсточника].Выполнить(ТекстЗапроса);

Этот метод хорош тем, что мы точно контролируем, какие поля обновляются. Секция WHERE гарантирует изменение нужной строки, а отсутствие ключевого поля в секции SET снимает проблему с IDENTITY_INSERT.

Решение 2: Перевод таблицы в режим "Объектные данные"

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

В чем преимущество этого подхода? Когда таблица помечена как объектная, 1С начинает работать с ней аналогично справочникам. В этом случае вместо менеджера записи используется объектная модель (СоздатьОбъект()), и при вызове Записать() платформа генерирует корректный SQL-запрос UPDATE, где ключ используется только для идентификации строки (в секции WHERE), а не для изменения данных. Это автоматически решает проблему прав доступа к полю-идентификатору.

Решение 3: Настройка свойств "Только чтение" и "Выражение для вставки"

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

  1. Свойство "Только чтение": Установите это свойство в значение Истина для всех полей, которые не должны обновляться (включая ключевое поле IDENTITY).
  2. Свойства "Выражение для вставки" и "Выражение для обновления": Это мощный инструмент маппинга. Если вы пропишете для ключевого поля в выражении для вставки слово DEFAULT, то 1С при попытке выполнить INSERT передаст серверу инструкцию использовать значение по умолчанию (автоинкремент самого SQL).

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

Решение 4: Программное управление записываемыми полями

В современных версиях платформы (8.3.5+) для наборов записей внешних источников доступен метод УстановитьЗаписываемыеПоля(). Рассмотрим, как это можно применить для решения нашей задачи. Мы можем явно указать платформе, какие колонки должны участвовать в операции записи, исключив из них проблемный идентификатор.

Проанализируем пример кода:


НаборЗаписей = ВнешниеИсточникиДанных.УчетВесовогоМатериала.Таблицы.ОсновнаяТаблицаУчета.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.НомерСтроки.Установить(СтрокаТЗ.НомерСтроки);
НаборЗаписей.Прочитать();

// Если запись найдена
Если НаборЗаписей.Количество() > 0 Тогда
    Запись = НаборЗаписей[0];
    Запись.ЗагруженоВ1С = 1;
    
    // Указываем, что записывать нужно ТОЛЬКО поле ЗагруженоВ1С
    МассивПолей = Новый Массив;
    МассивПолей.Добавить("ЗагруженоВ1С");
    НаборЗаписей.УстановитьЗаписываемыеПоля(МассивПолей);
    
    НаборЗаписей.Записать(Истина); // Истина - замещение
КонецЕсли;

Важное замечание: При использовании Записать(Истина) в необъектных данных 1С все равно попытается выполнить DELETE, а затем INSERT. Если ваша цель — именно UPDATE без удаления, лучше вернуться к Решению 1.

Рекомендации по выбору драйвера

Иногда странное поведение 1С при работе с внешними источниками связано с используемым драйвером ODBC. Проанализируем строку ошибки из примера: используется SQL Server Native Client 11.0. Это довольно старый драйвер. Для более стабильной работы и корректной трансляции типов данных рекомендуется использовать современные драйверы, такие как ODBC Driver 17 for SQL Server или выше. Новые версии драйверов лучше обрабатывают метаданные и реже вызывают ошибки несоответствия типов при записи.

Итоги

Подведем итог нашему разбору. Ошибка IDENTITY_INSERT возникает из-за попытки 1С перезаписать значение автоинкрементного столбца. Для эффективного решения проблемы мы рекомендуем:

  1. Использовать метод Выполнить() для прямого SQL-запроса UPDATE — это самый контролируемый способ.
  2. Перевести таблицу в разряд "Объектных данных", если требуется постоянная работа через объектную модель 1С.
  3. Тщательно проверять настройки свойств "Только чтение" в конфигураторе для всех полей внешнего источника.

Выбор конкретного метода зависит от архитектуры вашего решения, но в большинстве случаев прямой SQL-запрос оказывается наиболее быстрым и простым в реализации вариантом.

← На главную