В практике разработчика 1С часто встречаются ситуации, когда система выдает крайне странные ошибки в совершенно безобидных местах. Например, при попытке прочитать значение константы через метод Получить() или при обращении к следующему элементу выборки через Следующий(). Сообщение системы при этом гласит: «В данной транзакции уже происходили ошибки!». Рассмотрим подробнее, почему это происходит и как найти истинную причину сбоя, которая обычно скрыта гораздо глубже.
Для начала проанализируем поведение платформы «1С:Предприятие 8.3». Когда мы записываем объект (например, справочник Контрагенты), платформа открывает транзакцию. Если внутри этой транзакции — в любом месте, будь то подписка на событие, код в модуле объекта или процедура записи связанного справочника — возникает исключение, транзакция помечается как «битая» (Transaction Rollback State).
Критически важно понимать: даже если вы обернули проблемный участок кода в блок Попытка...Исключение, транзакция в базе данных уже считается невалидной. Любое последующее обращение к данным (чтение константы, выполнение запроса или метода Следующий() у выборки) приведет к аварийной остановке с системным сообщением. В данном случае ошибка на методе Получить() константы ИспользоватьВерсионированиеОбъектов — это лишь симптом того, что «отравление» транзакции произошло ранее.
В таких конфигурациях, как «Комплексная автоматизация 1.1» или «УПП 1.3», при записи нового контрагента программно создается основной договор. Разберем по шагам, что происходит в этот момент:
УстановитьНовыйКод() для договора.Как мы видим из обсуждения, именно ошибка при установке нового кода в справочнике ДоговорыКонтрагентов стала первопричиной каскада проблем.
Если проблема вызвана сбоем в автоматической нумерации (особенно часто это случается после перехода на платформу 8.3, восстановления базы из архива или массового импорта данных), необходимо сбросить кэш нумератора. Платформа 8.3 активно кэширует номера для повышения производительности, и иногда этот кэш «залипает».
Для исправления ситуации воспользуемся методом ОбновитьНумерациюОбъектов(). Мы можем создать простую обработку и выполнить в ней следующий код:
// Обновление нумерации для конкретного типа объектов
ОбновитьНумерациюОбъектов(Метаданные.Справочники.ДоговорыКонтрагентов);
// Или обновление для всех объектов метаданных (универсальный подход)
ОбновитьНумерациюОбъектов();
Этот метод очищает кэш номеров в памяти сервера и заставляет систему заново вычислить следующий свободный номер, исходя из фактически существующих записей в базе данных.
Иногда ОбновитьНумерациюОбъектов() не помогает, если в базе есть записи, нарушающие логику автонумерации. Проанализируем ситуацию, когда автоматический механизм «спотыкается». Рассмотрим пример запроса, который поможет найти проблемные коды:
ВЫБРАТЬ ПЕРВЫЕ 10
Договоры.Код КАК Код,
Договоры.Ссылка КАК Ссылка
ИЗ
Справочник.ДоговорыКонтрагентов КАК Договоры
УПОРЯДОЧИТЬ ПО
Договоры.Код УБЫВАЮЩИЙ
Посмотрим на результат. Если вы видите коды типа «999» при длине кода 3 или коды с символами, которые нельзя инкрементировать (например, префикс закончился на букву, за которой нет цифр), механизм УстановитьНовыйКод() не сможет выдать новое значение. В этом случае необходимо вручную отредактировать «крайние» номера, освободив диапазон для автоматики.
Если причина ошибки не очевидна, воспользуемся отладчиком. Проанализируем состояние программы в момент возникновения исключения:
Попытка...Исключение), посмотрите на «Стек вызовов».ПередЗаписью, ПриЗаписи или УстановитьНовыйКод.Рассмотрим пример кода, который часто маскирует проблему:
Попытка
НовыйОбъект.Записать();
Исключение
// Ошибка перехвачена, но транзакция уже "испорчена"
ЗаписьЖурналаРегистрации("Ошибка записи", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
// Любой следующий вызов к БД вызовет ошибку транзакции
ЗначениеКонстанты = Константы.ВажныйПараметр.Получить();
В данном случае, чтобы избежать путаницы, необходимо либо гарантировать выход из процедуры сразу после обработки исключения, либо использовать Ролбэк (отмену) всей операции.
Для систем, работающих в режиме совместимости с ранними версиями (как КА 1.1), важно учитывать следующие моменты:
Во-первых, проверьте права доступа. Несмотря на то, что автор темы имел «Полные права», иногда в серверном режиме при выполнении фоновых заданий или специфических подписок код может выполняться от имени пользователя с ограниченными правами. В таких случаях использование УстановитьПривилегированныйРежим(Истина) в общем модуле может помочь, но только если проблема в правах, а не в «битой» транзакции.
Во-вторых, обратите внимание на настройки Технологического Журнала. Если ошибка плавающая, настройте сбор событий EXCP. Это позволит увидеть текст исходной ошибки (например, «Нарушение уникальности номера»), которая произошла за миллисекунды до того, как система выдала сообщение об ошибке метода Получить().
Подводя итог, скажем: если вы видите ошибку «Ошибка при вызове метода контекста (Получить)» или «(Следующий)» с упоминанием транзакции, не ищите проблему в этих методах. Проверяйте всё, что выполнялось ранее в этой же транзакции, и в первую очередь — механизмы автонумерации объектов.