Перенос данных между конфигурациями разных поколений — например, из 1С:Комплексная автоматизация 1.1 (или УПП 1.3) в Комплексную автоматизацию 2.4 — всегда таит в себе множество подводных камней. Одним из таких неочевидных препятствий является механизм кэширования «1С:Конвертации данных 2.1» (КД2). В процессе выгрузки документов программисты часто сталкиваются с ситуацией, когда в базе-источнике в табличной части присутствуют разные номенклатурные позиции со своими уникальными сериями, но в итоговом файле выгрузки XML оказывается лишь одна серия, а вторая бесследно исчезает или подменяется первой.
В этой статье мы подробно разберем, почему возникает подобная проблема, проанализируем внутренние механизмы кэширования КД2, выясним роль параметра КлючВыгружаемыхДанных и рассмотрим, как правильно спроектировать правила конвертации объектов (ПКО) для подчиненных справочников, чтобы избежать потери данных.
Рассмотрим практическую ситуацию. В выгружаемом документе (например, в «Требовании-накладной») содержатся две разные позиции номенклатуры, у каждой из которых есть своя серия. При этом текстовые наименования серий абсолютно одинаковы, но они принадлежат разным товарам, имеют разных владельцев и разные уникальные идентификаторы (GUID) в базе-источнике:
8bc4e391-3e31-11e9-a56b-28924acd4010)8bc4e393-3e31-11e9-a56b-28924acd4010)Несмотря на то, что в логах выгрузки регистрируется обработка обеих серий, в результирующем XML-файле сохраняется только одна из них. Давайте детально разберем по шагам, почему так происходит.
Для оптимизации процесса выгрузки и предотвращения дублирования данных в XML-файле, обработка выгрузки КД2 использует внутреннюю таблицу соответствий выгруженных объектов (кэш выгрузки). Когда система встречает ссылку на объект (например, на справочник или документ), она выполняет следующие действия:
Нпп (номер по порядку, например, <Ссылка Нпп="125">).<Ссылка Нпп="125"/>, указывающая на ранее выгруженную структуру.По умолчанию в качестве ключа кэширования КД2 использует внутреннее строковое представление ссылки объекта источника — системный аналог функции ЗначениеВСтрокуВнутр(Источник). Это гарантирует абсолютную уникальность: две разные серии с одинаковыми наименованиями, но разными GUID, будут обработаны как два независимых объекта.
Проблема возникает в тот момент, когда разработчик в обработчике ПКО ПередВыгрузкойОбъекта принудительно переопределяет этот ключ вручную:
КлючВыгружаемыхДанных = Источник.Наименование;
Давайте проанализируем, к чему это приводит. Переопределяя КлючВыгружаемыхДанных строковым наименованием серии (например, "с/н 04/03/2019"), мы заставляем систему кэшировать данные не по уникальной ссылке, а по текстовому представлению. Происходит следующая последовательность событий:
Нпп. Ключ регистрируется в кэше.КлючВыгружаемыхДанных, который снова равен строке "с/н 04/03/2019".Нпп на первую серию. В итоге, при загрузке в базу-приемник у второго товара либо подставится чужая серия первого товара, либо поле вовсе очистится из-за несоответствия владельцев.
Чтобы избежать этой коллизии и при этом сохранить преимущества кэширования для ускорения выгрузки, мы должны обеспечить гарантированную уникальность ключа выгрузки. Если нам действительно необходимо переопределить ключ программно (например, для исключения дублей или при выгрузке виртуальных данных), хорошей практикой является использование комбинации уникальных идентификаторов самого объекта и его владельца.
Разберем правильный пример заполнения обработчика ПередВыгрузкойОбъекта для ПКО СерииНоменклатуры:
// Формируем гарантированно уникальный ключ на основе GUID самой серии и GUID ее владельца
КлючВыгружаемыхДанных = Строка(Источник.УникальныйИдентификатор()) + "/" + Строка(Источник.Владелец.УникальныйИдентификатор());
Если в источнике у серий отсутствует GUID (например, это плоская таблица или внешние данные), но есть уникальный код и наименование в разрезе владельца, можно использовать комбинированную строку:
КлючВыгружаемыхДанных = "СправочникСерии_" + СокрЛП(Источник.Владелец.Код) + "_" + СокрЛП(Источник.Код) + "_" + СокрЛП(Источник.Наименование);
При таком подходе КД2 корректно распознает серии как разные объекты, и обе структуры со своими реквизитами благополучно попадут в результирующий XML-файл.
У начинающих разработчиков часто возникает вопрос: «А что если просто установить в настройках ПКО флаг "Не запоминать выгруженные объекты"? Нужен ли тогда КлючВыгружаемыхДанных?»
Выясним физический смысл этой настройки. Если взвести флаг «Не запоминать выгруженные объекты», то система КД2 действительно перестанет помещать обработанные объекты этого правила в глобальный кэш. Проблема с дублированием ключей исчезнет, так как при встрече каждой серии система будет выгружать её структуру целиком заново.
Однако этот подход имеет критические недостатки:
Использовать флаг «Не запоминать выгруженные объекты» для справочников уровня номенклатуры, контрагентов или серий категорически не рекомендуется. Этот флаг предназначен для выгрузки неповторяющихся «тяжелых» данных (например, движений регистров накопления) или виртуальных вспомогательных узлов.
Проанализируем еще одно частое заблуждение: связана ли ручная установка КлючВыгружаемыхДанных с флагом ПКС «Получить значение из входящих данных».
Прямой жесткой зависимости на уровне ядра платформы нет. Однако на практике эти механизмы часто используются совместно при решении нестандартных задач конвертации:
ВходящиеДанные, переданной из вышестоящего правила выгрузки.Источник. Соответственно, КД2 не может автоматически рассчитать его уникальный внутренний идентификатор.КлючВыгружаемыхДанных в обработчике ПКО. Если этого не сделать, все генерируемые «на лету» виртуальные объекты склеятся в кэше КД2 в один единственный элемент, и перенос завершится ошибкой или потерей информации.
Помимо тонкостей работы самой КД2, при переносе серий номенклатуры важно учитывать кардинальные различия в архитектуре учета этих объектов между старыми конфигурациями (КА 1.1, УПП 1.3) и новыми решениями на ERP-платформе (КА 2.4, ERP 2, УТ 11).
Рассмотрим ключевые различия, которые необходимо заложить в правила конвертации до начала переноса:
СерииНоменклатуры жестко подчинен справочнику Номенклатура. Каждая серия привязана к конкретной карточке товара.ПолитикиУчетаСерий (например, «Учет себестоимости по сериям», «Управление остатками серий» или «Справочное указание серий»).Вида номенклатуры. Поэтому в процессе конвертации данных часто приходится динамически (в коде обработчиков) создавать новые виды номенклатуры, разделяя исходные виды на те, у которых товары велись по сериям, и те, у которых серийного учета не было. Это необходимо для корректного наложения политик учета серий в приемнике.Учитывая эти архитектурные аспекты и правильно управляя кэшированием через КлючВыгружаемыхДанных, вы сможете построить отказоустойчивый и быстрый процесс переноса серийных номеров, исключающий дублирование, путаницу и потерю аналитики в целевой базе данных.