Отношение один к разным типам объектов

134
26 июля 2019, 19:50

Я не знаю, есть ли какой-то готовый термин, поэтому в заголовок вынес "один-к-разным-типам-объектов", но это не термин из 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) к решению подобной задачи, какой вариант более удобен в реальных системах.

Answer 1

Можно пойти по пути создания на таблице OrderEntry двух полей EntityType и EntityId. При этом поле EntityType будет иметь низкую селективность, а проконтролировать ограничение EntityId как внешнего ключа я вообще не представляю себе как.

Встречал на практике вот этот вариант и он был очень даже работоспособен. Проверка целостности в этом случае, естественно, осуществляется уже не на уровне БД. Индекс должен быть композитный - сразу по двум полям.

Другой вариант - сделать на таблице OrderEntry два nullable столбца - один OrderId, другой OpportunityId и заполнять либо тот, либо другой. Ну, неплохой вариант как кажется.

Он не масштабируется. В тех системах, с которыми я работал - количество таких таблиц со временем увеличивалось до 20-30.

И последнее, что приходит в голову - это сделать две разных таблицы OrderEntiry - одна будет OrderEntryForOrder, другая - OrderEntryForOpportunity. Тоже вариант, который мне нравится, но меньше чем предыдущий: как мне кажется будет сложнее писать запросы к базе.

Аналогично.

READ ALSO
Как проксировать сайт с заданными cookies?

Как проксировать сайт с заданными cookies?

Есть сервис например: myservicecom, я авторизован в этом сервисе

148
Сохранит куки curl php

Сохранит куки curl php

Почему такой код не сохраняет куки?

157
Копирование строк таблицы mysql php

Копирование строк таблицы mysql php

Как скопировать одну строку таблицы в эту же таблицу?

157
Добавить свое поле в запрос SELECT

Добавить свое поле в запрос SELECT

Подскажите пожалуйста есть код, который делает копию полей в таблице

128