Внешний идентификатор сущности может измениться у поставщика. Как спроектировать связь с локальной моделью, чтобы не потерять историю?
Нельзя использовать изменяемый внешний идентификатор как единственный постоянный идентификатор локальной сущности. Следует завести собственный стабильный идентификатор, а связь с поставщиком хранить отдельно: как соответствие между источником, текущим внешним идентификатором и локальной сущностью.
Такой подход сохраняет внутренние ссылки и историю даже при изменении идентификатора у внешней системы. При этом нужно явно определить правила уникальности, обновления соответствия и обработки конфликтов.
В распределённых системах каждая система обычно владеет собственной моделью данных и правилами идентификации. Внешний идентификатор может быть уникальным только в пределах конкретного поставщика, зависеть от миграции данных или изменяться при переносе сущности.
Проблема стала особенно заметной при интеграции нескольких источников, консолидации данных и замене внешних систем. Локальной системе потребовалась независимая идентичность сущности, не зависящая от жизненного цикла поставщика.
Предположим, локальная система хранит клиента с идентификатором поставщика в качестве первичного ключа. Поставщик изменил этот идентификатор или передал ту же сущность под новым значением. Простая замена ключа может нарушить внешние ключи, ссылки в документах, аудит и историю операций.
Если вместо изменения записи создать нового клиента, возникнет дубликат. Это приведёт к ошибкам в отчётности, повторной обработке заказов и расхождениям между системами. Дополнительный риск появляется, если одинаковые внешние идентификаторы могут существовать у разных поставщиков.
В локальной модели сущность получает собственный неизменяемый идентификатор. В отдельной таблице соответствий хранятся как минимум источник данных, внешний идентификатор, локальный идентификатор сущности, статус соответствия и время его изменения.
Уникальность обычно задаётся составным правилом: один внешний идентификатор уникален в пределах конкретного источника, но не обязательно глобально. Для одной локальной сущности может существовать несколько соответствий, если она объединяет данные из нескольких систем.
При получении сообщения сначала ищут соответствие по паре «источник — внешний идентификатор». Если поставщик сообщает новый идентификатор с явной связью со старым, обновляют соответствие, сохраняя прежнюю запись в журнале изменений. Если такой связи нет, автоматическое слияние по одному признаку опасно: нужно использовать согласованные правила сопоставления или отправлять случай на разбор.
Историю соответствий лучше не уничтожать физическим удалением. Это позволяет повторно обработать старое сообщение, расследовать происхождение данных и поддержать ссылки на прежний идентификатор. Однако хранение истории не отменяет необходимости контролировать активность соответствий: старый идентификатор может быть помечен как неактивный и перенаправляться на локальную сущность.
У этого решения есть цена: усложняется модель данных, поиск требует обращения к таблице соответствий, а синхронизация становится чувствительной к порядку сообщений. Если внешний идентификатор гарантированно неизменяем, глобально уникален и принадлежит системе-владельцу, отдельная связь может быть избыточной, но это свойство должно быть подтверждено контрактом, а не предположено.
Интернет-магазин получает сведения о товарах от двух поставщиков. Оба используют числовые идентификаторы, а один поставщик меняет их после переноса каталога. Вариант с использованием числа как локального ключа прост, но приводит к конфликтам между поставщиками и потере истории после миграции.
Вариант с поиском товара по названию и характеристикам не требует таблицы соответствий, но даёт ложные совпадения при изменении описания и плохо объясняет принятое решение. Вариант с ручным сопоставлением надёжен для исключений, но не масштабируется для массовой загрузки.
Выбрана локальная сущность с внутренним идентификатором и таблицей соответствий, уникальной по источнику и внешнему идентификатору. При миграции поставщик передаёт связь старого и нового идентификаторов, после чего новое значение становится активным, а старое сохраняется как исторический алиас. В результате заказы и отчёты продолжают ссылаться на одну локальную сущность, а загрузку можно безопасно повторить.
1. Достаточно ли хранить только текущий внешний идентификатор?
Нет, если система должна обрабатывать запоздалые сообщения или расследовать прошлые операции. Старое значение следует сохранять как историческое соответствие с периодом действия или признаком неактивности. Иначе сообщение со старым идентификатором будет ошибочно принято за новую сущность либо не будет сопоставлено вовсе.
2. Можно ли определить сущность по комбинации атрибутов вместо идентификатора?
Комбинация атрибутов может использоваться для поиска кандидатов на сопоставление, но обычно не является надёжным постоянным ключом. Имя, адрес или артикул могут измениться, повторяться или быть исправлены задним числом. Автоматическое слияние допустимо только при подтверждённой уникальности и понятных правилах разрешения конфликтов.
3. Как обработать сообщение с новым внешним идентификатором без явной ссылки на старый?
Нельзя безусловно считать его переименованием существующей сущности. Сначала применяют формальные признаки из контракта поставщика: специальный идентификатор миграции, неизменяемый бизнес-ключ или подтверждённое событие переноса. Если надёжного признака нет, сообщение помещают в очередь на сопоставление или создают новую сущность по правилам предметной области, фиксируя решение в аудите.