Я не знаю, есть ли какой-то готовый термин, поэтому в заголовок вынес "один-к-разным-типам-объектов", но это не термин из 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) к решению подобной задачи, какой вариант более удобен в реальных системах.
Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId. При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение EntityId как внешнего ключа я вообще не представляю себе как.
Встречал на практике вот этот вариант и он был очень даже работоспособен. Проверка целостности в этом случае, естественно, осуществляется уже не на уровне БД. Индекс должен быть композитный - сразу по двум полям.
Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId, другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется.
Он не масштабируется. В тех системах, с которыми я работал - количество таких таблиц со временем увеличивалось до 20-30.
И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry - одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы к базе.
Аналогично.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Есть сервис например: myservicecom, я авторизован в этом сервисе
Подскажите пожалуйста есть код, который делает копию полей в таблице