При интеграции 1С с внешними базами данных, такими как Microsoft Access или MS SQL Server, через механизм Внешние источники данных, разработчики часто сталкиваются с архитектурным ограничением платформы. Если стандартный механизм записи 1С не подходит (например, требуется сложный SQL-запрос через ADO), мы вынуждены прерывать штатную запись. Однако после этого форма «застывает» в состоянии нового объекта. Рассмотрим подробнее, как решить эту задачу и заставить форму осознать, что объект уже существует в базе.
Когда мы работаем с управляемой формой объектных данных (Справочники, Документы или Таблицы внешних источников), платформа использует так называемое расширение формы объекта. Это расширение отслеживает состояние реквизита Объект. Если поле Объект.Ссылка пустое, форма считает себя формой нового объекта и отображает в заголовке текст «(создание)».
Типичный сценарий, который мы проанализируем:
ПриЗаписи (или ПередЗаписью) на сервере разработчик устанавливает Отказ = Истина, чтобы заблокировать стандартную запись 1С.INSERT во внешнюю базу.В результате реквизит Объект.Ссылка остается пустым. Если пользователь нажмет «Записать» еще раз, логика сработает повторно, создавая дубликат записи во внешнем источнике. Нам необходимо выяснить причину, по которой форма не обновляется, и найти способ подставить полученную ссылку обратно в интерфейс.
Проанализируем наиболее изящный способ, который позволяет обновить данные формы без её закрытия и повторного открытия. Этот метод заключается в принудительной синхронизации серверного объекта с данными формы.
Разберем алгоритм действий по шагам:
ЗначениеВРеквизитФормы, чтобы обновить расширение формы.Посмотрим на пример реализации в коде формы:
&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Блокируем стандартную запись платформы
Отказ = Истина;
// Выполняем запись через свой механизм (например, ADO)
НовыйИдентификатор = ЗаписатьВоВнешнийИсточник(ТекущийОбъект);
Если НовыйИдентификатор <> Неопределено Тогда
// Создаем ссылку на основе полученного ID
// ИмяИсточника и ИмяТаблицы должны соответствовать метаданным
НоваяСсылка = ВнешниеИсточникиДанных.ИмяИсточника.Таблицы.ИмяТаблицы.СоздатьСсылку(НовыйИдентификатор);
// Получаем объект по ссылке
ОбъектБД = НоваяСсылка.ПолучитьОбъект();
// Ключевой момент: обновляем данные формы
ЗначениеВРеквизитФормы(ОбъектБД, "Объект");
// Снимаем признак модифицированности, так как данные уже в базе
ЭтаФорма.Модифицированность = Ложь;
КонецЕсли;
КонецПроцедуры
Этот подход хорош тем, что ЗначениеВРеквизитФормы автоматически обновляет внутреннее состояние расширения формы. Поле Объект.Ссылка перестает быть пустым, и форма переходит в режим редактирования существующего объекта. Заголовок окна также обновится автоматически.
Выясним, почему вообще может потребоваться «костыль» с ручной записью. Зачастую это происходит из-за того, что в конфигурации 1С для таблицы внешнего источника неверно указаны Ключевые поля.
Если во внешнем источнике данных (например, в Access) поле ID является автоинкрементным (Auto-increment), 1С должна уметь с ним работать штатно. Проанализируем настройки в Конфигураторе:
Число или УникальныйИдентификатор).Если первичный ключ настроен верно, 1С сама выполнит INSERT, получит созданный ID и заполнит Объект.Ссылка без использования Отказ = Истина. Это самый правильный путь, исключающий необходимость написания сложного кода поддержки формы.
Рассмотрим ситуацию, когда нам нужно заранее знать, какая ссылка будет у объекта. Для этого существует метод УстановитьСсылкуНового(). Однако, как было замечено в обсуждении на форуме, этот метод работает только в паре со штатным механизмом записи.
Если вы вызываете Отказ = Истина, то зарезервированная ссылка «сгорает», так как транзакция записи с точки зрения объектной модели 1С не состоялась. Поэтому данный метод бесполезен при ручном управлении SQL-запросами, но крайне полезен, если вы хотите передать GUID во внешнюю систему до того, как объект будет окончательно записан в базу 1С.
Если работа с методом ЗначениеВРеквизитФормы вызывает сложности (например, из-за особенностей структуры внешнего объекта), можно воспользоваться менее «джедайским», но надежным способом — переоткрытием формы.
Схема работы следующая:
ПослеЗаписи (если запись прошла успешно и ссылка получена) мы закрываем текущую форму.Недостаток этого метода в том, что визуально пользователь может заметить «моргание» окна, а также могут быть потеряны некоторые временные данные формы (не связанные с объектом). Тем не менее, это гарантирует 100% корректное состояние расширения формы, так как оно инициализируется заново на основе существующей записи в базе.
Пример кода для вызова переоткрытия:
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
// Если это был новый объект и теперь у нас есть ссылка
Если ПараметрыЗаписи.Свойство("НоваяСсылка") Тогда
ПараметрыОткрытия = Новый Структура("Ключ", ПараметрыЗаписи.НоваяСсылка);
Закрыть();
ОткрытьФорму("ВнешнийИсточникДанных.Имя.Таблица.ФормаОбъекта", ПараметрыОткрытия);
КонецЕсли;
КонецПроцедуры
Мы проанализировали проблему синхронизации управляемой формы с внешними данными. Главный вывод: платформа 1С жестко связывает состояние формы с наличием значения в Объект.Ссылка. При программной записи во внешние источники самым технологичным решением является использование ЗначениеВРеквизитФормы на сервере. Это позволяет сохранить контекст работы пользователя и обеспечить корректное поведение интерфейса без лишних манипуляций с окнами.
Также всегда стоит проверять настройки метаданных: возможно, ваша проблема решается простой установкой галочки «Ключевое поле», что позволит 1С работать с внешней базой в нативном режиме.