#java #c_sharp #sql #entity_framework #архитектура
Я не знаю, есть ли какой-то готовый термин, поэтому в заголовок вынес "один-к-разным-типам-объектов",
но это не термин из EF-диаграмм (один-ко-многим, многие-ко-многим и т.п.)
Вот с какой задачей на архитектуру я столкнулся. Меня интересует каким образом можно
выразить (в первую очередь на слое реляционном, во вторую - на уровне классов) отношение
один-к-разным типам объектов.
Пример из практики, несколько упрощённый. В базе данных существует таблица денежных
переводов (MoneyTransfers) между пользователями сайта с полями:
идентификатор перевода MoneyTransferId,
участник-отправитель SourceUserId,
участник-получатель DestinationUserId,
величина перевода AmountRur.
В базе есть таблица заказов (Orders). Это сайт групповых закупок, участники объединяются
для того, чтобы сэкономить на доставке товара из-за рубежа.
И вот для учёта кто за что кому когда платил (а бардак там бывает знатный, особенно
на какую-нибудь чёрную пятницу) сделана ещё одна таблица, OrderEntries:
идентификатор OrderEntryId,
сумма AmountRur,
идентификатор перевода MoneyTransferId,
идентификатор заказа OrderId.
Т.е. фактически это связь многие-ко-многим между Order и MoneyTransfer с промежуточной
таблицей. Удобно в практике: можно оплатить заказ несколькими переводами, можно одним
переводом оплатить сразу несколько заказов - и по всему этому удобно строить отчёты.
Проблема появляется, когда помимо заказов-закупок девочки захотели продавать друг
другу лачки. Вот тут и появилась вторая таблица в дополнение к Orders — таблица сделок
(Opportunitites), а с ней появилась и проблема, вынесенная в заголовок.
Таблиц у меня две, при этом в OrderEntries мне нужно указать к чему относится эта
запись - к Order или к Opprtunity.
Как быть?
Можно пойти по пути объединения таблиц Order и Opportunity в одну сущность. При этом
допустим такая ORM как Entity Framework предлагает три варианта для хранения данных:
Table Per Hierarchy, Table Per Type и Table Per Concrete Type. Причём все способы имеют
значительные недостатки, либо в удобстве работе, либо с производительностью.
Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId.
При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение
EntityId как внешнего ключа я вообще не представляю себе как.
Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId,
другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется.
И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry -
одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который
мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы
к базе.
Кажется, я перебрал все возможные варианты, ничего не упустил? (Если знаете другой
- напишите)
Меня интересуют какой-то типовой подход (best practice) к решению подобной задачи,
какой вариант более удобен в реальных системах.
Ответы
Ответ 1
Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId. При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение EntityId как внешнего ключа я вообще не представляю себе как. Встречал на практике вот этот вариант и он был очень даже работоспособен. Проверка целостности в этом случае, естественно, осуществляется уже не на уровне БД. Индекс должен быть композитный - сразу по двум полям. Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId, другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется. Он не масштабируется. В тех системах, с которыми я работал - количество таких таблиц со временем увеличивалось до 20-30. И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry - одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы к базе. Аналогично.
Комментариев нет:
Отправить комментарий