При работе с обменом данными в 1С через механизм "Конвертация Данных 2" (КД2) разработчики часто сталкиваются с нетипичным поведением: объект в базе-источнике был помечен на удаление, но после обмена в базе-приемнике он оказался непосредственно удален, а не просто помечен. Эта ситуация может привести к потере данных и нарушению логики работы информационной системы. Давайте подробно разберем, почему это происходит и как можно решить данную проблему.
Прежде всего, важно понимать, как КД2 интерпретирует различные команды удаления, поступающие из файла обмена или прямого подключения.
Механизм КД2 по-разному реагирует на непосредственное удаление объекта в источнике и его пометку на удаление:
Удалить() без предварительной пометки), КД2 генерирует в файле обмена специальную секцию <УдалениеОбъекта>. Эта секция является прямой и однозначной инструкцией для базы-приемника также непосредственно удалить соответствующий объект. При получении такой команды система не будет пытаться установить пометку удаления, а сразу выполнит физическое удаление.ПометкаУдаления = Истина), то по умолчанию КД2 не всегда автоматически передает этот признак пометки на удаление в базу-приемник. Чтобы пометка на удаление была перенесена, необходимо выполнить дополнительные настройки в правилах конвертации объектов (ПКО).Теперь, когда мы понимаем базовые принципы, рассмотрим конкретные шаги для диагностики и решения проблемы.
Как показал опыт из форума (Сообщение 5), одной из частых причин нежелательного поведения может быть некорректная настройка правил регистрации объектов. Правила регистрации определяют, какие объекты и с какими условиями будут выгружены из базы-источника. Если условие в правилах регистрации не выполняется для помеченного на удаление объекта, он может быть выгружен не так, как ожидалось, или же система может воспринять его отсутствие в выгрузке как команду к удалению.
Пример из практики: Мы сталкивались с ситуацией, когда в правилах регистрации стояло условие Проведен = Истина. Если документ был помечен на удаление, он, скорее всего, также был отменен (не проведен). Из-за этого условия документ не выгружался как "измененный" с пометкой удаления. В некоторых случаях, если объект ранее был выгружен и существовал в приемнике, а затем перестал выгружаться из источника (потому что не прошел условие регистрации), система обмена в приемнике могла интерпретировать это как отсутствие объекта в источнике и, в зависимости от других настроек, инициировать его удаление.
Что нужно сделать:
Проведен = Истина точно стоит убрать для объектов, которые должны быть выгружены с пометкой, так как помеченные документы часто становятся непроведенными.Как мы уже выяснили, КД2 по умолчанию не всегда передает признак пометки на удаление. Для корректного переноса этого признака нам потребуется явным образом настроить Правила Конвертации Объектов (ПКО).
Разберем процесс по шагам:
Нам необходимо получить значение свойства ПометкаУдаления объекта-источника и передать его в базу-приемник как дополнительный параметр. Это делается в обработчике события "ПередВыгрузкой" соответствующего ПКО:
// Пример кода для обработчика "ПередВыгрузкой" в ПКО объекта-источника
// Предполагаем, что "Источник" - это текущий объект базы-источника.
// Передаем значение ПометкаУдаления как дополнительный параметр.
Если Источник.ПометкаУдаления Тогда
Параметры.Вставить("ПометкаУдаленияИсточника", Истина);
Иначе
Параметры.Вставить("ПометкаУдаленияИсточника", Ложь);
КонецЕсли;
// Или более короткий вариант:
// Параметры.Вставить("ПометкаУдаленияИсточника", Источник.ПометкаУдаления);
Здесь мы создаем параметр с именем "ПометкаУдаленияИсточника" и присваиваем ему логическое значение свойства ПометкаУдаления из объекта-источника. Этот параметр будет доступен в обработчиках ПКО в базе-приемнике.
Теперь в базе-приемнике, в обработчике события "ПриЗагрузке" или "ПослеЗагрузки" соответствующего ПКО, нам нужно проверить значение этого переданного параметра. Если объект найден в приемнике и параметр указывает, что в источнике он был помечен на удаление, тогда следует программно установить Объект.ПометкаУдаления = Истина и записать объект.
// Пример кода для обработчика "ПриЗагрузке" или "ПослеЗагрузки" в ПКО объекта-приемника
// Предполагаем, что "Объект" - это текущий загружаемый объект базы-приемника,
// а "Параметры" содержит параметры, переданные из источника.
Если Параметры.Свойство("ПометкаУдаленияИсточника") Тогда
Если Параметры.ПометкаУдаленияИсточника И Объект.Ссылка.ПометкаУдаления = Ложь Тогда
// Если объект в источнике помечен на удаление, а в приемнике нет,
// устанавливаем пометку удаления.
Объект.УстановитьПометкуУдаления(Истина);
// Записывать объект здесь не обязательно, если это ПриЗагрузке,
// так как он будет записан автоматически.
// Если это ПослеЗагрузки, то возможно потребуется Объект.Записать();
КонецЕсли;
Иначе
// Важно: если параметр не был передан, это может означать,
// что логика выгрузки пометки удаления не была настроена в источнике,
// или это обычный объект.
// Если объект был ранее помечен на удаление в приемнике, но в источнике
// он теперь не помечен, можно снять пометку:
// Если Объект.Ссылка.ПометкаУдаления И НЕ Объект.ПометкаУдаления Тогда
// Объект.УстановитьПометкуУдаления(Ложь);
// КонецЕсли;
КонецЕсли;
Мы используем метод УстановитьПометкуУдаления(Истина), чтобы корректно пометить объект на удаление. Обратите внимание, что в обработчике "ПриЗагрузке" объект еще не записан, и его запись произойдет автоматически после выполнения обработчика. Если же вы используете "ПослеЗагрузки" и нужно сохранить изменения, может потребоваться явный вызов Объект.Записать().
В КД2 существует специальный глобальный обработчик события "ПриПолученииУдаления", который позволяет перехватывать команды на удаление, поступающие с обменом (Сообщение 6). Этот обработчик срабатывает, когда в файле обмена присутствует секция <УдалениеОбъекта>, которая, как мы помним, является инструкцией для непосредственного удаления.
Как использовать:
В этом обработчике вы можете установить параметр Отказ = Истина, чтобы предотвратить непосредственное удаление объекта в приемнике. Вместо этого вы можете реализовать свою логику, например, установить пометку удаления для объекта.
// Пример кода для глобального обработчика "ПриПолученииУдаления"
// (Находится в основном модуле или специальном модуле обмена)
// Параметры:
// ОбъектУдаления - ссылка на объект, который должен быть удален.
// Отказ - булево, если Истина, то удаление не будет выполнено.
Процедура ПриПолученииУдаления(ОбъектУдаления, Отказ)
// Мы не хотим, чтобы объект удалялся непосредственно.
Отказ = Истина;
// Вместо непосредственного удаления, пометим его на удаление.
Если ТипЗнч(ОбъектУдаления) = Тип("ДокументСсылка.ВашДокумент") Тогда
// Проверяем, что объект не является помеченным на удаление
Если НЕ ОбъектУдаления.ПометкаУдаления Тогда
Попытка
ОбъектУдаления.УстановитьПометкуУдаления(Истина);
Исключение
// Обработка ошибки, если не удалось установить пометку удаления
ЗаписатьВЖурналРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Ошибка,
ОбъектУдаления, , "Ошибка установки пометки удаления при обмене: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
// Добавьте аналогичную логику для других типов объектов
КонецПроцедуры;
Важные замечания:
Отказ = Истина, так как это полностью блокирует автоматическое удаление. Убедитесь, что ваша альтернативная логика (пометка на удаление) всегда срабатывает корректно.Если вышеуказанные шаги не помогли, или вы хотите убедиться, что нет другого кода, вызывающего непосредственное удаление, следует провести тщательный поиск в конфигурации приемника (Сообщение 7).
Удалить(): Ищите программный вызов метода ПолучитьОбъект().Удалить() или Объект.Удалить() в следующих местах:
ПриЗаписи, ПередЗаписью) соответствующего типа.ПриЗагрузке, ПослеЗагрузки).Используйте полнотекстовый поиск по конфигурации для поиска строки ".Удалить(".
ОбменДанными.ЗагрузкаФлаг ОбменДанными.Загрузка часто используется в обработчиках ПриЗаписи() или ПередЗаписью() объектов для предотвращения выполнения дополнительной логики (например, проверок или движений регистров) во время процесса обмена данными. Однако, при получении команды на непосредственное удаление через секцию <УдалениеОбъекта>, этот признак может вести себя иначе или быть недоступным для предотвращения самого удаления.
Если вы нашли код, который вызывает Удалить() в обработчиках ПриЗаписи или ПередЗаписью, и он не обернут в условие Если НЕ ОбменДанными.Загрузка Тогда ... КонецЕсли;, то он может срабатывать во время обмена, приводя к нежелательному удалению.
Что нужно проверить:
Удалить().
// Пример использования ОбменДанными.Загрузка
Если Не ОбменДанными.Загрузка Тогда
// Здесь код, который не должен выполняться при загрузке данных обмена
// Например, вызов Объекта.Удалить()
// Объект.Удалить();
КонецЕсли;
Проблема непосредственного удаления объектов вместо установки пометки на удаление при обмене через КД2 может быть вызвана несколькими факторами, от некорректных правил регистрации до специфического кода в обработчиках или глобальных правилах. Систематический подход, включающий проверку правил регистрации, настройку ПКО для явной передачи пометки удаления, анализ глобального обработчика "ПриПолученииУдаления" и тщательный поиск кода непосредственного удаления в конфигурации, поможет вам выявить и устранить причину. Мы надеемся, что эти рекомендации помогут вам эффективно управлять обменом данными и обеспечить целостность ваших информационных баз. Для быстрого контроля результатов миграции и поиска расхождений в учете после сеансов обмена целесообразно использовать сервис для автоматического сравнения проводок между базами 1С через COM-соединение.